Spring面试篇
文章目录
Spring的循环依赖问题怎么解决
循环依赖问题指的是在依赖注入过程中两个类互相依赖,这会导致实例化的过程混乱,因为一个类实例化需要另一个类已经实例化了,一般有三种循环依赖问题:
- 构造函数依赖循环,这个解决不了
- setter的依赖循环,其中bean是多例(prototype)
- setter的依赖循环,其中bean是单例。
Spring仅仅对第三种进行了解决。第一种在new的时候就进行不下去了,无法生成对象;第二种由于无穷无尽的循环会生成很多的bean,最后导致oom。
如何解决
spring用一个三级缓存解决了,总的来说就是在一个类没有初始化的时候提前暴露bean存到三级缓存中,然后进行这个类初始化完成之后就放回第一层缓存中。
创建 BeanA: Spring 首先将 BeanA 的实例存储在三级缓存中。 在创建 BeanA 的过程中,发现需要注入 BeanB。
创建 BeanB: Spring 将 BeanB 的实例存储在三级缓存中(因为 BeanB 也需要 BeanA)。 在创建 BeanB 的过程中,Spring 发现 BeanA 还未完全初始化,所以从三级缓存中获取 BeanA 的代理对象。
注入依赖: 当 BeanA 创建完成后,Spring 会将 BeanB 注入到 BeanA 的字段中。 同样地,BeanA 会注入到 BeanB 的字段中,完成依赖注入。
在三级缓存这一块,主要记一下 Spring 是如何支持循环依赖的即可,也就是如果发生循环依赖的话,就去 三级缓存 singletonFactories 中拿到三级缓存中存储的 ObjectFactory 并调用它的 getObject() 方法来获取这个循环依赖对象的前期暴露对象(虽然还没初始化完成,但是可以拿到该对象在堆中的存储地址了),并且将这个前期暴露对象放到二级缓存中,这样在循环依赖时,就不会重复初始化了!
Bean的生命周期
大的可以分为四个部分:
- bean创建阶段:通过调用反射api完成bean的实例化
- 依赖注入:为bean设置相关属性和依赖
- 初始化bean:首先检查是否实现了Aware包下面的各种aware接口,例如beanname,beanclassloader,beanfactory,其次再检查是否实现了Postbeanprocess接口,执行postbeanbeforeinitialization,再看有没有实现bean初始化方法InitializationBean和xml的init-method,最后再用postBeanAfterInitialization
- 销毁,disposableBean和destory-bean

依赖注入的三种方式
- 字段注入:上面加@Autowired
- 构造器注入:官方推荐
- setter注入:通过setter方法注入
Bean会有线程安全问题吗
首先来看看bean的作用域,常见的有:
- singleton:默认的bean是单例的
- prototype:每次获取都是不一样的bean
- request:一次http请求就一个bean
如果作用范围是prototype,那不会有线程安全问题,一次获取就有一个bean。但是如果是单例的bean会有线程安全问题,可以通过以下几个方式解决:
- 尽量使用无状态bean
- 使用ThreadLocal
- 加锁synchronized
SpringMVC执行流程
- 客户端发送http请求,首先由DispatcherServlet接收
- DispatcherServlet去HandlerMapping里面找(这是一个哈希表,存储了请求路径和controller的映射关系)
- 找到了对应的Controller,先去通过适配器HandlerAdapter,再去请求Controller
- 调用完成后返回一个视图和模型ModelAndView。
- DispatcherServlet找视图解析器ViewResolver进行解析。
- 解析得到的Model结合View进行渲染返回请求者

spring的事务传播逻辑
- TransactionDefinition.PROPAGATION_REQUIRED:外部方法没有开启事务,那就自己开启事务,且开启的事务之间相互独立不打扰;如果外部方法有事务,那就与外部同生共死,如果外部事务回滚自己也回滚。外部事务中的一个子事务回滚那所有都回滚。且如果内部事务异常被捕获,外部事物还是会回滚
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:外部事务回滚,内部的new不回滚。内部事务回滚,如果被catch了就不会造成外部事务回滚,如果没有catch就会回滚。(上一个是有无catch都会造成外部事物回滚)
- TransactionDefinition.PROPAGATION_NESTED:与上一个是反的,外部事务回滚会造成内部回滚,自身回滚也是看catch,如果catch了外部事物就不会滚
@Transactional注解使用
可以使用在方法和类上,使用在类上就是给所有方法都加上事务。常用参数有5个,事务隔离级别(读未提交,读提交,可重复读,串行化),传播行为,超时时间(在指定的时间内未完成回滚),是否只读,触发回滚的异常类型
spring自调用导致失效问题
由于Transaction这个注释用到了aop,进行事务的对象都是代理对象。如果是自己调用就无法拦截到这个内部调用,所以事务会失效。这个时候可以获取其代理对象。
1 |
|