java框架面试题
Spring面试题
spring的优点
spring提供了IOC容器,可以让我们把各个对象交给Spring管理.简化了开发,对AOP和事务等进行了支持,方便集成各种框架,还对java的一些API进行了封装.
什么是控制反转(IOC)? 什么是依赖注入(DI)?
控制反转:IOC将对象的创建销毁初始化,权交给spring,是一种工厂模式,通过工厂模式实现接口与业务的分离
依赖注入:DI他的前提是IOC的环境,依赖注入指的是在配置文件中就能指定类创建的属性
在 Spring 中,有哪几种依赖注入方式?
三种注入方式,分别是
- 用set方法注入:在xml中配置bean中属性值或者依赖的对象,这是最常用的一种方式,spring先调用类的默认构造函数实例化之后,通过反射的方式调用setter方法注入属性值.
- 构造函数注入:它保证了一些必要的属性在bean实例化时就得到设置,确保了bean在实例化之后就可以使用,构造方法注入分为俩种,一种为按类型传入type和按索引传入index.俩种也可以联合使用
- 注解方式进行注入:在xml中配置包扫描,用@component("名")配置被扫描的类,可以用@value设置普通属性的值
谈谈springAOP的理解
AOP一般称为面向切面,可用于日志,事务,统计访问等.用于将多个对象的都需要用到的公共逻辑抽取并封装,为一个可重用的模块.
AOP实现关键在于代理模式,分为静态代理和动态代理,spring的aop属于动态代理.
解释Spring支持的几种bean的作用域
spring支持的作用域由scope来定义分为
- singleton:默认,每个容器中只有一个bean实例
- prototype:每一次都创建一个新的对象
- request在web项目中,spring创建这个类之后,将类存入到reques中
- session:应用在web项目中,spring创建这个类之后,将类存入到session中
- globalsession:应用在web项目中,和porlet相关.日过没有这种环境的话就基于session
spring是线程安全的吗
有状态的bean:有存储数据功能,有实例变量的对象,可以保存数据的,是非线程安全的.
无状态的bean:一次操作不能保存数据,没有实例变量,时不变类是线程安全的.
一般情况下,只有无状态的bean才可以在多线程环境下共享,大部分情况下bean是无状态的,因此pring是线程安全的如果bean是有状态的话,就需要自行保证线程安全.
可采用ThreadLocal方式,或者将scope声明为prototype让每一个线程都创建一个prototype实例.但这样会消耗很多的内存空间
spring事务的实现原理
spring事务的本质其实就是对数据库对事务的支持,没有数据库对事务的支持,spring是无法提供事务功能的.真正的数据库层的事务提交和回滚是通过数据库的日志实现的.
spring事务的种类
spring支持编程式事务和声明式事务
- 编程式事务管理使用transactiontemplate
- 声明式事务是建立在AOP之上的.其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能便知道拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务.
实际开发中声明式事务用的比较多
spring事务的传播行为
PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事物,如果当前存在事务,就加入该事务
PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务就加入该事务,如果当前不存在事务,就以非事务运行
PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务如果当前不存在事务就抛出异常
PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都会创建新事物
PROPAGATION_NOT_SUPPORTED:以非实物方式执行操作,如果当前存在事务就把当前事务挂起
PROPAGATION_NEVER:以非事物方式运行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行.如果当前没有事务,则按REQUIRED属性执行
https://www.jianshu.com/p/25c8e5a35ece
事务的隔离级别
ISOLATION_DEFAULT:这个是默认使用,数据库的隔离级别
ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事物可以看到这个事务未提交的数据
ISOLATION_READCOMMITTED:读已提交,保证另一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有数据的更新记录
ISOLATION_REPEATABLE_READ:可重复读,保证一个事物修改提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新
ISOLATION_SERIALIZABLE:串行读,事务被处理为顺序执行
bean的生命周期
实例化->属性赋值->初始化->销毁
spring自动装配
- no:默认的方式是不进行自动装配的,通过手工改设置ref属性来进行装配bean
- byName:通过bean的名称进行装配,如果一个bean的property与另一个bean的name相同,就进行自动装配
- byType:通过参数的数据类型进行自动装配,如果一个bean的property与另一个bean的property相同,就进行自动装配
- construnctor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配.
- autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。
autowired和resource的区别
@autowired是按照类型注入对象,可以配合@qualifer一起使用,只按照byType注入
@Resources:按照传入的name自动注入,有俩个参数,指定了name就是byName注入,指定了type就是byType注入,都不指定就是byName注入
spring用了哪些设计模式
- 工厂模式:beanfactory就是简单工厂模式的体现,用来创建对象的实例
- 单例模式:bean默认为单例模式
- 代理模式:spring的aop功能用到了jdk的动态代理
- 模板方法:spring中的djbctemplate和jpatemplate
- 观察者模式:定义对象一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被自动更新,如spring中的监听器实现applicationListener
解释一下Spring AOP里面的几个名词
- 连接点:可以被拦截到的方法,能够被增强的方法,这些方法就可以称为连接点
- 切入点:被增强被拦截的方法
- 通知:增加的内容通常都是封装成一个方法,我们称之为通知
- 引介:给类层面增加,给原有的类添加一些新的属性和方法(在开发中通常是给方法进行增加)
- 目标对象:被增强的对象
- 织入是指把增强应用到目标对象来创建新的代理对象的过程。 spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
- 代理对象:最后生成的返回对象
- 切面:多个通知和多个切入点的集合
spring通知的类型
- 前置通知:在目标方法之前进行操作
- 后置通知:在目标方法执行之后进行操作
- 环绕通知:在目标方法执行之前和之后都能进行操作
- 异常通知:在方法抛出异常退出时执行的通知
- 最终通知:无论代码是否有异常都会执行
@component和@Bean的区别是什么
作用对象不同.@Component注解作用于类,而@Bean注解于方法
@component注解通常是通过类路径扫描来自动侦测以及自动装配到spring容器中,@Bean注解通常是在标有该注解的方法中定义产生的bena,告诉spring这是某个类的实例,当我们需要用它的时候还给我
@Bean注解比@component注解自定义性更强.比如第三方库的类需要用到spring容器的时候,就只能通过@Bean注解来实现
SpringMVC
什么是springmvc?
springmvc全称springwebmvc,spring可以很便捷的集成springmvc框架,他通过把model,view,controller分离将web层进行解耦,简化了开发,方便开发人之间的协作开发
springmvc的访问流程
1.用户请求发送至前段控制器DIspatcherServlet
2.DispatcherServlet收到请求之后,调用HandlerMapping处理器映射器,请求获取Handle
3.处理器映射器根据url找到具体的处理器,生成处理器对象及处理器拦截器,一并返回给DispatcherServlet
4.dispatcherServlet调用HandlerAdapter处理器适配器
5.HandlerAdapter结果适配调用具体处理器Handler
5.HandlerAdapter结果适配调用具体处理器Handler
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Hander执行结果ModelAndView返回给DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewResoler视图解析器进行解析
9.ViewResolver解析后返回具体view
10.DispatcherServlet交给模板引擎对View进行渲染视图
11.模板引擎渲染后返回视图给DispatcherServlet
12disPathcherServlet响应给用户
springmvc中如何解决get|POST请求乱码问题
tomcat中默认的编码为iso8859
对于get请求可以更改tomcat中server.xml中的connector设置为utf-8编码就能解决问题
post请求在web.xml中添加过滤器设置编码为utf-8即可.
springmvc中的异常处理
将异常抛给spring框架,由spring框架来进行处理,我们只需要配置简单的异常处理器,在异常处理器中添加视图页面即可
SpringMvc的控制器是不是单例模式,如果是怎么解决线程安全问题
是单例模式,在多线程访问的时候有线程安全的问题,解决方法就是不要写成员变量,但其实使用@Autowired注入的成员变量不会有线程安全问题,因为@Autowired注入进来的其实是jdk动态代理的对象,代理类会从ThreadLocal中获取真正的Reqeust对象并调用相应的方法.因此不会产生线程安全问题.
相关链接:https://www.xingmal.com/article/article/1233935175935725568
mybatis
Mybatis的优缺点
优点
基于sql语句编程,相当灵活,不会对应用程序或者数据库的现有的设计造成影响,sql写在xml里,接触sql与程序代码的耦合,便于统一管理.
与各种数据库兼容,能够很好的和spring进行整合,是一个半ORM的框架;
缺点
sql语句编写工作量较大,字段多关联表时,出现的错误性较大
sql语句依赖数据库导致数据库移植性交叉,不能随意更换数据库
{}和${}的区别
{}是预编译处理,${}是字符串替换
因此${}会有sql注入问题,而#{}没有
如何获取自动生成的主键值
insert方法总是返回一个int值,这个值代表的是插入的行数
如果采用自动增长策略,主动生成的键值在insert方法执行完成后可以被设置到传入的参数对象中
<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>
insert into names (name) values (#{name})
</insert>
name name = new name();
name.setname(“fred”);
int rows = mapper.insertname(name);
// 完成后,id已经被设置到对象中
system.out.println(“rows inserted = ” + rows);
system.out.println(“generated key value = ” + name.getid());
mybatis一级,二级缓存
mybatis中使用缓存来提高性能,当查询数据时,会先从缓存中取数据,如果缓存中没有再到数据库中去查询
mybatis的缓存分为俩种,一级缓存和二级缓存,一级缓存是sqlsession级别的
sqlsession对应着一次数据库会话.数据库会话不是永久的,因此sqlsession也不是永久的,在每次访问数据库的时候都要创建它.
二级缓存是mapper级别的
一级缓存
一级缓存是默认开启的,sqlsession没有关闭之前,再去查询时会先从session中取数据,不会重新发送sql
一级缓存在以下情况会失效
- 查询之前执行了增删改的操作
- 手动清空缓存
- 俩次查询的条件不一致,缓存也会失效
- 如果俩个查询在不同的sqlsession中
二级缓存
mybatis默认不开启二级缓存
全局作用域,一个namespace对应一个缓存
不同namespace查出的数据,会放到自己对应的查询中
二级缓存存在于SqlSessionFactory 生命周期中
使用
- 在配置文件中开启二级缓存
- 对应mapper中添加cache标签
- pojo实现serializable接口
查询的数据都会先放到一级缓存中,只有会话关闭,以及缓存中的数据才会转到二级缓存中
注意
查询频率很高,更新频率很低时使用,二级缓存,最好在单表操作
建议使用第三方的差集来做缓存比如redis
mybatis是否支持懒加载,原理是什么
mybatis支持一对一与一对多的懒加载,可以在配置文件中设置lazyLoadingEnabled=true开启
原理是使用cglib创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如当调用get方法适,烂机器invoke()发现get方法的返回值是null值,那么就会发送事先保存好的sql把B查询上来,然后调用set方设置值.这就是懒加载的原理
什么是mybatis的接口绑定,实现的方式有哪些
接口绑定,就是在mybatis中任意定义接口,然后把接口里面的方法和sql语句绑定,我们直接调用接口方法就可以.
有俩种实现方式,一种是通过注解进行绑定,在接口的方法上面加上@select,@update等注解,里面包含sql语句绑定
另一种就是通过xml里面写sql来绑定,这种情况下,要制定xml映射文件里面的namepace必须为接口的全路径名称.
一般xml绑定用的比较多
使用mybatis接口的时候有那些要求
- mapper接口方法名和mapper.xml中定义的每个sql的id相同
- mapper接口方法的输入参数类型和mapper.xml中每个sql的parameterType的类型相同
- mapper接口返回的参数和mapper.xml中每个sql的resultType的类型相同
- Mapper.xml文件中的namespace即使mapper接口的路径类型