Spring Bean的生命周期和循环依赖

Spring Bean的生命周期

Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean

总的来说,bean的生命周期主要分为以下4个步骤

对象的实例化—>对象的初始化—>使用---->销毁

具体来说,流程图

在这里插入图片描述

文字说明

1、 启动spring容器,也就是创建beanFactory(bean工厂),
一般用的是beanFactory的子类applicationcontext,
applicationcontext比一般的beanFactory要多很多功能,比如aop、事件等。
通过applicationcontext加载配置文件,或者利用注解的方式扫描将bean
的配置信息加载到spring容器里面。

2、 加载之后,spring容器会将这些配置信息(java bean的信息),封装成BeanDefinition对象
BeanDefinition对象其实就是普通java对象之上再封装一层,
赋予一些spring框架需要用到的属性,比如是否单例,是否懒加载等等。

3、 然后将这些BeanDefinition对象以key为beanName,
值为BeanDefinition对象的形式存入到一个map里面,
将这个map传入到spring beanfactory去进行springBean的实例化。

4、 传入到pring beanfactory之后,利用BeanFactoryPostProcessor接口这个扩展点
去对BeanDefinition对象进行一些属性修改。

5、 开始循环BeanDefinition对象进行springBean的实例化,springBean的实例化也就
是执行bean的构造方法(单例的Bean放入单例池中,但是此刻还未初始化),
在执行实例化的前后,可以通过InstantiationAwareBeanPostProcessor扩展点
(作用于所有bean)进行一些修改。

6、 spring bean实例化之后,就开始注入属性,
首先注入自定义的属性,比如标注@autowrite的这些属性,
再调用各种Aware接口扩展方法,注入属性(spring特有的属性),
比如BeanNameAware.setBeanName,设置Bean的ID或者Name;

7、 初始化bean,对各项属性赋初始化值,初始化前后执行BeanPostProcessor
(作用于所有bean)扩展点方法,对bean进行修改。
初始化前后除了BeanPostProcessor扩展点还有其他的扩展点,执行顺序如下:
(1). 初始化前 postProcessBeforeInitialization()
(2). 执行构造方法之后 执行 @PostConstruct 的方法
(3). 所有属性赋初始化值之后 afterPropertiesSet()
(4). 初始化时 配置文件中指定的 init-method 方法
(5). 初始化后 postProcessAfterInitialization()
先执行BeanPostProcessor扩展点的前置方法postProcessBeforeInitialization(),
再执行bean本身的构造方法
再执行@PostConstruct标注的方法
所有属性赋值完成之后执行afterPropertiesSet()
然后执行 配置文件或注解中指定的 init-method 方法
最后执行BeanPostProcessor扩展点的后置方法postProcessAfterInitialization()

8、 此时已完成bean的初始化,在程序中就可以通过spring容器拿到这些初始化好的bean。

9、 随着容器销毁,springbean也会销毁,销毁前后也有一系列的扩展点。
销毁bean之前,执行@PreDestroy 的方法
销毁时,执行配置文件或注解中指定的 destroy-method 方法。
以上就是spring bean的整个生命周期
其实就是根据配置文件或注解信息,生成BeanDefinition,
循环BeanDefinition去实例化-》注入属性-》初始化-》销毁,在这4个阶段执行前后,
spring框架提供了一系列的扩展点。

spring Bean的各种扩展点

(1)、容器级扩展点(作用于所有bean):
BeanFactoryPostProcessor接口: 在循环初始化springbean之前,对BeanDefinition元数据做扩展处理
InstantiationAwareBeanPostProcessor接口: 在对象实例化前后扩展,作用于所有bean
BeanPostProcessor接口: 在对象初始化化前后扩展,作用于所有bean

(2)、Bean扩展点(作用于单个bean):
Aware接口: springBean实例化并且注入自定义属性之后
InitializingBean接口: springBean初始化时,执行构造方法结束,并且属性赋初始化值结束之后执行
DiposableBean接口: springBean销毁之前执行。

(3)、Bean自身的方法
包括了Bean本身调用的方法
通过配置文件中的init-method和destroy-method指定的方法(或者用注解的方式)
(4)、包括了AspectJWeavingEnabler,
ConfigurationClassPostProcessor,
CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。
工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

循环依赖的处理

循环依赖:一个或多个bean之间相互依赖,最终形成闭环。可以通过三级的缓存解决

所谓的三级缓存其实就是三个Map…spring内部有三级缓存:

  • singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
  • earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
  • singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。
@Service
public class ServiceA {

	@Autowired
	private ServiceB serviceB;
}

@Service
public class ServiceB {

	@Autowired
	private ServiceA serviceA;
}

下面用一张图告诉你,spring是如何解决循环依赖的:

为啥需要二级缓存
如果一个对象同时被两处引用,需进行实例化,此时如果没有二级缓存,两次从三级缓存中获取都是ObjectFactory对象,而通过它创建的实例对象每次可能都不一样的。

@Service
public class ServiceB {

	@Autowired
	private ServiceA serviceA;
}

@Service
public class ServiceC {

	@Autowired
	private ServiceA serviceA;
}

按照上图的流程可以把serviceA注入到serviceB,并且sServiceA的实例是从第三级缓存中获取的。假设不用第二级缓存,serviceA注入到serviceC的流程如图:

serviceA注入到serviceC又需要从第三级缓存中获取实例,而第三级缓存里保存的并非真正的实例对象,而是ObjectFactory对象。说白了,两次从三级缓存中获取都是ObjectFactory对象,而通过它创建的实例对象每次可能都不一样的。
为了解决这个问题,spring引入的第二级缓存。上面其实serviceA对象的实例已经被添加到第二级缓存中了,而在此时serviceA注入到serviceC时,只用从第二级缓存中获取该对象即可

为啥需要三级缓存
假设没有第三级缓存,只有第二级缓存(Value存对象,而不是工厂对象),这里肯定是需要考虑代理的情况的,比如A对象是一个被AOP增量的对象,B依赖A时,得到的A肯定是代理对象的,所以,三级缓存的Value是ObjectFactory,可以从里边拿到代理对象

参考:
springBean生命周期
Spring Bean的生命周期(非常详细)
Spring Bean的生命周期管理
spring如何解决循环依赖
Spring如何解决循环依赖
SpringBean生命周期

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面试高级开发的期间整理的面试题目,记录我面试遇到过的spring题目以及答案 目录 spring ThreadLocal的底层对象; 为什么@Service和@Repository放到实现类上面而不是接口类上面; spring 三种注入(就是从spring容器中将bean放入对象属性值中) Spring下描述依赖关系@Resource, @Autowired和@Inject的区别与联系 SpringBeanFactory和ApplicationContext的区别 谈谈Spring IOC的理解,原理与实现? bean的生命周期,详细看上面 SpringBoot自动装配的过程的原理: spring的缓存; spring是如何解决的循环依赖BeanFactory和FactoryBean有什么区别; Spring中用到的设计模式; SPI 机制(Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制), 很多地方有用到: AOP Spring的AOP的底层实现原理; 为什么jdk动态代理是必须是接口 两种动态代理的区别 AOP实现方式:aop注解或者xml配置;后来工具jar包aspects; aop的属性 事务 事务编码方式: 事务注意事项; 为什么同一个类A调用b方法事务,A方法一定要有事务(编码式的不用) @transaction多个数据源事务怎么指定数据源 传播特性有几种?7种; 某一个事务嵌套另一个事务的时候怎么办? REQUIRED_NEW和REQUIRED区别 Spring的事务是如何回滚的,实现原理; 抽象类和接口的区别,什么时候用抽象类什么时候用接口; StringBuilder和StringBuffer的区别 java值传递和引用传递

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值