zuul网关的作用
1.Zuul 包含了对请求的路由和过滤两个最主要的功能:其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。
而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础、
2.Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意: Zuul服务最终还是会注册进Eureka 提供=代理+路由+过滤 三大功能。
Ribbon和Feign的区别?
1.Ribbon都是调用其他服务的,但方式不同。
2.启动类注解不同,Ribbon是@RibbonClient feign的是@EnableFeignClients
3.服务指定的位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
4.调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。
什么是AOP(Spring的AOP理解):
OOP面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。
什么是 spring boot?
用来简化spring应用的初始搭建以及开发过程 使用特定的方式来进行配置(properties或yml文件)
创建独立的spring引用程序 main方法运行
嵌入的Tomcat 无需部署war文件
简化maven配置
自动配置spring添加对应功能starter自动化配置
spring boot来简化spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用
Springboot的优点
快速创建独立运行的spring项目与主流框架集成
使用嵌入式的servlet容器,应用无需打包成war包
starters自动依赖与版本控制
大量的自动配置,简化开发,也可修改默认值
准生产环境的运行应用监控
开发部署方便,后期与云计算平台集成方便(docker).
spring boot 核心配置文件是什么?
spring boot 核心的两个配置文件:
bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,且 boostrap 里面的属性不能被覆盖
application (. yml 或者 . properties):用于 spring boot 项目的自动化配置
spring和springboot
SpringBoot 是一个脚手架项目,主要是用特有的方式来快速的配置和启动基于Spring的项目,让我们开发基于Spring的企业级应用变得更加简单。
什么是 spring cloud?
spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署
接口和抽象类的区别?
1.接口是被类实现,抽象类是被子类继承
2.接口只能做方法申明,抽象类能做方法声明,也能做方法实现
3.接口中定义的变量是公共的静态的常量,抽象类中的变量是普通变量
4.接口是设计的结果,抽象类是重构的结果
get和post区别?
Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。2.Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制。GET在浏览器回退时是无害的,而POST会再次提交请求。GET产生的URL地址可以被Bookmark,而POST不可以。GET请求会被浏览器主动cache,而POST不会,除非手动设置。GET请求只能进行url编码,而POST支持多种编码方式。GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。GET请求在URL中传送的参数是有长度限制的,而POST么有。对参数的数据类型,GET只接受ASCII字符,而POST没有限制。GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。GET参数通过URL传递,POST放在Request body中
== 与 equals(重要)
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
Mybitas当中#$的区别
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
但是MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
重载和重写的区别(重要)
a)重载
简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
b)重写
重写指的是在Java的子类与父类中有两个名称、参数列表和返回值类型都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法。
重写是父类与子类之间的多态性,对父类的函数进行重新定义。
c)区别
重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载是一个类中多态性的一种表现。而重写是父类与子类之间的多态性,是对父类的函数进行重新定义。
sql中where和having的区别
用的地方不一样
where可以用于select、update、delete和insert into values(select * from table where ..)语句中。
having只能用于select语句中
执行的顺序不一样
where的搜索条件是在执行语句进行分组之前应用
having的搜索条件是在分组条件后执行的
即如果where和having一起用时,where会先执行,having后执行
子句有区别
where子句中的条件表达式having都可以跟,而having子句中的有些表达式where不可以跟;having子句可以用集合函数(sum、count、avg、max和min),而where子句不可以。
总结
1.WHERE 子句用来筛选 FROM 子句中指定的操作所产生的行。
2.GROUP BY 子句用来分组 WHERE 子句的输出。
3.HAVING 子句用来从分组的结果中筛选行
mybatis中的表名和数据库对应不上?
方案一:
在XML映射文件中使用的resultMap,优点:可以被重复使用。
通过里面的id标签和result标签来建立映射关系,由property和column分别指定实体类属性和数据表的列名。
方案二:
让字段的别名与实体类的属性名相同,优点:操作简单,容易理解。缺点:当这样的语句出现的次数过多的时候,到时冗余代码增多,这些别名不能重用。
方案三:
使用Map集合封装结果集,在MyBatis中字段名作为key,字段所对应的数据作为value。优点:可以在多表操作时使用。
方案四:
使用注解@Results和@Result
这两个注解与XML文件中的标签相对应: @Results对应resultMap @Result对应result
方案五:
通过配置属性来完成映射,Mybatis给我们提供了一种映射方式,如果属性的命名是遵从驼峰命名法的,数据列名遵从下划线命名, 那么可以使用这种方式,类似如下:
userName对应user_name;
userId对应user_id;
ArrayList 和 LinkedList 的区别是什么?
Arraylist:底层是基于动态数组,根据下表随机访问数组元素的效率高,向数组尾部添加元素的效率高;但是,删除数组中的数据以及向数组中间添加数据效率低,因为需要移动数组。
Linkedlist基于链表的动态数组,数据添加删除效率高,只需要改变指针指向即可,但是访问数据的平均效率低,需要对链表进行遍历。
1、对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
@Configuration的使用和作用
从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
注意:@Configuration注解的配置类有如下要求:
@Configuration不可以是final类型;
@Configuration不可以是匿名类;
嵌套的configuration必须是静态类。
一、用@Configuration加载spring
1.1、@Configuration配置spring并启动spring容器
1.2、@Configuration启动容器+@Bean注册Bean
1.3、@Configuration启动容器+@Component注册Bean
1.4、使用 AnnotationConfigApplicationContext 注册 AppContext 类的两种方法
1.5、配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)
@Configuation加载Spring方法
@Configuration配置spring并启动spring容器
@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)
@Configuation总结
@Configuation等价于<Beans></Beans>
@Bean等价于<Bean></Bean>
@ComponentScan等价于<context:component-scan base-package=”com.dxz.demo”/>
在使用dubbo过程中遇到哪些问题?如何解决?
1、同时配置了XML和properties文件,则properties中的配置无效
只有XML没有配置时,properties才会生效
2、dubbo默认会在启动时检查依赖是否可用,不可用就抛出异常,阻止spring初始化完成,check属性默认为true
测试环境下有些服务不关心或出现了循环依赖,将check设置为false
3、为了方便开发测试,线下有一个所有服务可用的注册中心,这时,如果有一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行
让服务提供者开发者,只订阅服务,而不注册正在开发的服务,通过直连测试正在开发的服务。设置dubbo:registry标签register属性为false
4、spring 2.x初始化死锁的问题
事件:在spring解析到dubbo:service时,就已经向外暴露了服务,而spring还在接着初始化其他bean,如果这时有请求进来,并且服务的实现类里有调用applicationContext.getBean()的方法,getBean线程和spring初始化线程的锁的顺序不一样,导致了线程死锁,不能提供服务,启动不了;
解决:不要在服务的实现类中使用applicationContext.getBean()如果不想依赖配置顺序,可以将dubbo:provider的deplay属性设置为-1,使dubbo在容器初始化完成后再暴露服务
5、服务注册不上
检查dubbo的jar包有没有在classpath中,以及有没有重复的jar包
检查暴露服务的spring配置有没有被加载
在服务提供者机器上测试与注册中心的网络是否可以ping通
6、出现RpcException:No provider available for remote service异常
这个异常表示没有可用的服务提供者;
检查连接的注册中心是否正确
到注册中心查看相应的服务提供者是否存在
检查服务提供者是否正常运行
7、出现“消息发送失败”异常
通常是接口方法的传入传出参数未实现Serializable接口
(1) 什么是正向代理?
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
(2) 什么是反向代理?
反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
MySQL 慢查询,全称 慢查询日志 ,它是 MySQL 提供的一种日志记录,用了记录在 MySQL 中响应时间超过阈值的语句。具体环境中,如果运行时间超过 long_query_time 值的 sql 语句,则会被记录到慢查询日志中。通常 long_query_time 的默认值为10,这也代表意思是运行10秒以上的 sql 语句时间。默认情况下,MySQL 是不会自动启动慢查询日志的,需要我们手动来设置这个参数。那么当然,如果我们不是用来将项目进行调优的话,一般不建议启动该参数,因为开启后,对于慢查询日志的性能多少会带来影响。
数据库的隔离级别?
ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
内连接,左连接,右连接是什么?
内连接关键字:inner join;左连接:left join;右连接:right join。 内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反
什么是 Spring Boot Stater ?
启动器是一套方便的依赖没描述符,它可以放在自己的程序中。你可以一站式的获取你所需要的 Spring 和相关技术,而不需要依赖描述符的通过示例代码搜索和复制黏贴的负载。
比如我们项目中使用 Sping data JPA 访问数据库,我们只需要在项目中的pom.xml文件中引入 spring-boot-starter-data-jpa 依赖项,你就可以完美进行。
1、接口的开发需要前端和服务端共同调试,要仔细阅读测试人员反映的bug信息,判断这个bug是服务端的bug还
是前端的bug。通常服务接口开发完成会使用postman工具进行测试,测试没有问题再提交到Git或SVN。
2、找到bug的出错点就可以根据bug信息进行修改。
3、修改完成需要前后端再次连调测试,按照测试人员提交的测试流程重新进行测试,测试通过将此bug置为已解决
1、前端与后端开发人员讨论确定接口。
接口讨论通过,形成接口文档 。
本项目专门设立一个api工程,在此工程定义接口,Spring Boot 集成Swagger,生成Swagger接口,前后端 开发
人员通过html查看接口文档的内容。
2、前端与后端开发人员按照接口文档进行开发。
怎么保证接口安全性?
就是微服务之间的认证,用户携带身份令牌和JWT令牌访问微服务,微服务获取jwt并完成授权。当微服务访问微服务,此时如果没有携带JWT则微服务会在授权时报错。因为项目中有很多都是微服务之间feign调用的。这地方我使用的Feign拦截器实现的。(实现的思路就是使用RequestContextHolder工具获取request相关变量,然后获取authorization携带的JWT令牌然后在下一次请求的时候携带JWT令牌传递过去就行了。)
怎么保证接口幂等性?
所谓的幂等性,我理解就是重复操作同一接口,返回的结果要一致,就是幂等,返回的结果不一致就是不幂等。我项目中幂等采用的流水消息记录表的方式,先判断有没有数据然后在操作,如果有数据则直接修改流水表的修改时间如果没有数据证明此操作是新增操作,直接放行,然后操作成功之后在添加数据到流水表中。
分布式事务我了解的有几种方式可以实现:1.两段式提交协议(2PC)2.事务补偿(TCC)3.消息队列实现最终一致,我们采用的就是消息队列实现最终一致方式实现的分布式事务。
订单微服务和学习微服务完成分布式事务,
1、支付成功后,订单服务向本地数据库更新订单状态并向消息表写入“添加选课消息”,通过本地数据库保证订单状态和添加选课消息的事务。。
2、定时任务扫描消息表,取出“添加选课任务”并向MQ发送消息。
3、学习服务接收到添加选课的消息,先查询本地数据库的历史消息表是否存在消息,存在则说明已经添加选课,否则向本地数据库添加选课,并向历史消息表添加选课消息。这里选课表和历史消息表在同一个数据库,通过本地事务保证。
4、学习服务接收到添加选课的消息,通过查询消息表判断如果已经添加选课也向MQ发送“完成添加选课任务的消息”,否则则添加选课,完成后向MQ发送“完成添加选课任务的消息”,
5、订单服务接收到完成选课的消息后删除订单数据库中消息表的“添加选课消息”,为保证后期对账将消息表的消息先添加到历史消息表再删除消息,表示此消息已经完成。
hashmap
hashmap如何实现扩容?
答案:hashmap的初始容量是16 默认加载因子是0.75 ,当数组中已存放的个数大于16*0.75(75%)的时候,会进行自动的二次幂扩容,创建一个新数组,新数组是原来数组的2倍长,然后遍历原来的数组,挨个把所有元素重新hash算法分配到相对应位置上。
简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
在put的时候,因为该方法不是同步的,假如有两个线程A,B它们的put的key的hash值相同,不论是从头插入还是从尾插入,假如A获取了插入位置为x,但是还未插入,此时B也计算出待插入位置为x,则不论AB插入的先后顺序肯定有一个会丢失
jvm 的主要组成部分?及其作用?
类加载器(ClassLoader)
运行时数据区(Runtime Data Area)
执行引擎(Execution Engine)
本地库接口(Native Interface)
组件的作用: 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码,运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能
redis内存淘汰策略?
如果redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略:
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
redis分布式锁?
分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。
可靠性
首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
互斥性。在任意时刻,只有一个客户端能持有锁。
不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
redis持久化的几种方式
Redis 持久化拥有以下三种方式:
快照方式(RDB, Redis DataBase)将某一个时刻的内存数据,以二进制的方式写入磁盘;
文件追加方式(AOF, Append Only File),记录所有的操作命令,并以文本的形式追加到文件中;
混合持久化方式,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能简单数据丢失的风险。
hashmap和hashtable区别?
1.Map是一个以键值对存储的接口。Map下有两个具体的实现,分别是HashMap和HashTable.
2.HashMap是线程非安全的,HashTable是线程安全的,所以HashMap的效率高于HashTable.
3.HashMap允许键或值为空,而HashTable不允许键或值为空.
4.继承关系不同:
HashTable
public class Hashtable<K,V> extends Dictionary<K,V>1.0
implements Map<K,V>, Cloneable, java.io.Serializable {}
HashMap
public class HashMap<K,V> extends AbstractMap<K,V>1.2
implements Map<K,V>, Cloneable, Serializable{}
异常体系?
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。下面将详细讲述这些异常之间的区别与联系:
1、Error与Exception
Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
BS/CS区别
BS架构与CS架构详解
1、CS(client/server)与BS(browser/serber)架构的区别
1)硬件环境不同
CS架构是建立在局域网上的,需要安装软件,要求有相同的操作系统,对计算机的配置要求较高。
BS架构是建立的广域网上的,有浏览器和操作系统就行,与操作系统无关(可以跨平台),对计算机电脑的配置要求较低。
2)安全要求不同
CS:一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。
BS:建立在广域网上,面向不可知的用户,对安全的控制力较弱。
3)软件维护
CS:开发维护成本较高,需要专业的技术人员完成,每一个客户端软件都需要进行升级更新
BS:维护简单方便,网页修改所有用户都会进行同步更新
4)用户体验
CS:客户端进行大量的业务处理然后交给服务端,所以客户端的响应速度比较快
BS:客户端与服务端的交互是请求响应式,需要动态刷新页面,所以响应速度较慢。
5)个性化功能
CS:操作界面漂亮、形式多样,可以充分满足客户自身的个性化要求。
BS:软件的个性化特点明显降低,难以实现传统模式下的特殊功能要求.
总结:
CS架构响应速度快,安全性强,个性化特点较强;但是开发维护成本较高,分布功能较弱,兼容性差,用户群固定
BS架构分布性强,客户端零维护,业务扩展简单;但是响应速度较慢,安全性较差。
软件的个性化特点明显降低,难以实现传统模式下的特殊功能要求
转发和重定向区别?
请求转发:
request.getRequestDispatcher(URL地址).forward(request, response)
处理流程:
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器。
请求转发
2)重定向:
response.sendRedirect(URL地址)
处理流程:
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。
重定向
以上两种情况,你都需要考虑Servlet处理完后,数据如何在jsp页面上呈现。图例是请求、响应的流程,没有标明数据如何处理、展现。
redis的持久化
1.RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化。
2.AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在
redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。
怎样保证线程安全性
线程安全是一个多线程环境下正确性的概念,也就是保证多线程环境下共享的可修改的状态的正确性,这里的状态反映在程序中其实可以看做是数据。
换个角度来看,如果状态不是共享的,或者不是可修改的,也就不存在线程安全问题,进而可以推理出保证线程安全的两个办法:第一个是封装,我们可以将对象内部状态隐藏保护起来。第二个是不可变。
线程安全需要保证几个基本特性:第一个是原子性,简单来说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现。第二是可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存中,volatile关键字就是负责保证可见性的。第三个是有序性,是保证线程内串行语义,避免指令重排等。
同步方法和同步块的区别
同步方法就是在方法前加关键字synchronized,然后被同步的方法一次只能有一个线程进入,其他线程等待。而同步方法则是在方法内部使用大括号使得一个代码块得到同步。同步块会有一个同步的”目标“,使得同步块更加灵活一些(同步块可以通过”目标“决定需要锁定的对象)。一般情况下,如果此”目标“为this,那么同步方法和同步块没有太大的区别。
另外,通过反编译可以看出,同步块比同步方法多了两个指令。因此同步方法是比同步块要快一些。
sql优化?
我们为了定位到有问题的sql,我们的controller方法执行时都回通过时间拦截器记录方法执行的时间。而且我们在安装mysql服务器的时候都会开启慢查询,我们可以查看慢查询的日志,找到运行慢的sql, 然后可以利用mysql的执行计划Explain+sql 根据显示的参数,来定位这条sql是否用到了全表扫描,在数据量大的情况下,全表扫描会严重影响sql的效率。然后分析一下这个sql是否可以简化(把* 修改为需要查询的字段),或者是建立相关的索引,如果sql采用的是子查询,我们尽量把他修改为连接查询,因为子查询要创建临时表和删除临时表,这样的话会影响效率。
如果在并发量大的时候,只通过sql优化是解决不了数据库的压力,因为大部分的场景都是读多写少的,这样就可以采用mysql的读写分离。
在使用索引的过程中
(1)在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引不起作用。只有“%”不在第一个位置,索引才会生效,
(2)OR前后的两个条件中的列都是索引时,索引才会生效,否则,索引不生效
(EXPLAIN SELECT * from t_product WHERE PRODUCT_CODE='PN201610120023'; # 0.012s --> 0.003)
(3)WHERE字句的查询条件里有不等于号(WHERE column!=…),MYSQL将无法使用索引
(4)如果WHERE字句的查询条件里使用了函数(如:WHERE DAY(column)=…),MYSQL将无法使用索引
2.使用子查询进行SELECT语句嵌套查询,可以一次完成很多逻辑上需要多个步骤才能完成的SQL操作。
子查询虽然很灵活,但是执行效率并不高。
执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响。
EXPLAIN SELECT id,name,age from
(SELECT id,name,age from t_user WHERE age=19) b
WHERE b.age=19;
优化:
可以使用连接查询(JOIN)代替子查询,连接查询时不需要建立临时表,其速度比子查询快。
Log4j日志级别?
log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
ALL 最低等级的,用于打开所有日志记录。
TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF 最高等级的,用于关闭所有日志记录。
如果将log level设置在某一个级别上,那么比此级别优先级高的log都能打印出来。例如,如果设置优先级为WARN,那么OFF、FATAL、ERROR、WARN 4个级别的log能正常输出,而INFO、DEBUG、TRACE、 ALL级别的log则会被忽略。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。
从我们实验的结果可以看出,log4j默认的优先级为ERROR或者WARN(实际上是ERROR)。
git和svn区别
1.Git是分布式的,SVN是集中式的
SVN必须有一个服务器版本库就放在一个中央服务器。所有开发人员都是与服务器进行交互的。
Git更倾向于分布式开发,每台计算机上都有一个完整的本地版本库,和服务器上的一模一样。所以即使没有网络也一样可以Commit,查看历史版本记录,创建项 目分支等操作。也有中心服务器,仅仅是为了方便交换大家的修改。
去中心化的好处?
操作处理速度快
安全性更高。Git每个人的电脑都有完整的版本库,SVN集中式版本控制的中央服务器要是出了问题,所有人都没法干活了,一次需要定期备份,并且是整个SVN都得备份
不依赖网络
2.Git把内容按元数据方式存储,而SVN是按文件
SVN保存前后变化的差异数据
Git只关心文件数据的整体发生变化,更像是把文件做快照,文件没有改变时,分支只想这个文件的指针不会改变,文件发生改变,指针指向新版本
3.Git没有一个全局版本号,而SVN有
SVN版本号进行控制,每次操作都会产生一个高版本号
Git采用40 位长的哈希值作为版本号,没有先后之分
4. Git的内容的完整性要优于SVN
GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏
5.分支不同
Svn 创建分支,其实就是创建了一个新的文件夹(目录)并拥有实际的文件的。相当于拷贝了一份源文件。创建完分支后,影响全部成员,每个人都会拥有这个分支。拉分支相当于copy时间较慢。多分支并行开发较重。
Git可以在任意一个提交点(commit point)开启分支,并没有创建文件夹,你甚至看不到任何的改变。创建一个分支,就是多了一个索引文件,记录这个分支的变化,占用很小的空间。拉分支时间较快,拉分支只是创建文件的指针和HEAD。用户可以在同一个文件夹中,快速的切换不同的分支。每个分支,都是独立的,在这个分支里想做什么都可以,对其他分支没有一点影响。比较适合多分支并行开发。
6.管理权限不同
svn的权限管理相当严格,可以按组、个人针对某个子目录的权限控制
Git没有严格的权限管理控制,只有账号角色划分
7.工作流程不同
SVN每次更改文件之前都得update操作,有冲突,会打断提交动作
Git开始工作前进行fetch操作,完成开发工作后push操作,有冲突解决冲突。git的提交过程不会被打断,有冲突会标记冲突文件