Spring中Bean生命周期

源码顺序图

image.png

Bean的元数据搜集

  1. **Java对象**的创建中,只是通过 加载到**方法区的Class对象**为模板,创建出对应的对象
  2. 而被**Spring管理的Bean对象**中,除了**基础的类信息**以外,还包括了**对象的元信息**,例如像 **单例还是多例**@Scope,是否进行**懒加载** @Lazy,是否**依赖于其他的Bean** @DependOn
  3. Spring会通过扫描文件的方式,xml、或是@Configuration等获取到相关的Bean的元数据信息
  4. 在扫描完毕元数据信息后,每个Bean的元数据信息会封装成一个 **BeanDefinition** 对象
  5. 所有的Bean的 **BeanDefinition** 对象都会封装到 **BeanDefinitionMap** 中,key是Bean的名称,value是对应的 **BeanDefinition对象**
  6. 此时**Bean对象没有被真正创建**,仅仅是做了元数据的收集工作

BeanFactoryPostProcessor

  1. 在元数据的收集工作完成后,可以获取到Bean的元数据信息对象 **BeanDefinition**
  2. 此时会对所有的 **BeanDefinition** 进行遍历执行 **BeanFactoryPostProcessor** 的方法
  3. @Value的实现类 就是 BeanFactoryPostProcessor的子类
  4. 这里的方法可以对 **Bean的元数据信息进行获取或修改操作**,但是一般不会这样使用

通过反射创建Bean对象

对Bean的属性进行依赖注入

主要的缓存集合

  1. **singletonObjects**一级缓存,ConcurrentHashMap,在所有对象完成初始化后,最终都会进入到一级缓存中,保存的是bean的名称与bean的关系
  2. **earlySingletonObjects**二级缓存,HashMap,主要用于解决在Bean的生命周期中,需要**生成代理对象的情况**,存放的是Bean的名称和bean。在流程结束后会从二级缓存中获取到bean,放入一级缓存中
  3. **singletonFactories**三级缓存,HashMap,**用于打破循环**,存放的是 bean的名称和对应的lambda表达式,**用于判断创建的是 代理对象还是普通对象**
  4. **earlyProxyReferences****AOP组件内的集合**,如果bean出现循环依赖后,则需要提前创建代理对象并放入二级缓存中,此时会将该bean加入到该集合中,在bean的真正到判断创建代理对象的时候,**通过判断该集合从而判断是否仍然需要创建代理对象**
  5. **singletonsCurrentlyInCreation**,bean在**创建的过程**中会**处于在这个集合内**,保存的是Set集合,Bean的名称,在bean创建的时候会加入这个集合,在bean加载完毕后,则会从这个集合中移除,**用于判断是否存在循环依赖**

当Bean A和B相互依赖时的初始化流程

  1. 调用**doGetBean(beanA)**流程,此时会将beanA的名称加入到 **singletonsCurrentlyInCreation**
  2. 判断**singletonObjects**一级缓存和**earlySingletonObjects**二级缓存中是否存在该bean,存在则直接返回
  3. 调用**addSingletonFactory()**,会将一个**lambda表达式**存放到 **singletonFactories** 三级缓存中,其中value保存的是一个lambda表达式作用是用于生成原始对象,会根据**判断是否包含**对应的**BeanPostProcessors** 从而**判断生成的是代理对象还是普通对象**。此时对象没有进行初始化操作。
  4. 此时判断到BeanA有依赖注入属性B,此时则会去调用**doGetBean(beanB)**流程,BeanB也重复上面123的流程
  5. 此时判断到BeanB存在依赖注入属性A,此时会先寻找一级缓存中是否存在,然后在**singletonsCurrentlyInCreation**判断到BeanA还没有初始化完毕,即**出现了循环依赖**
  6. 此时会从二级缓存、三级缓存的顺序寻找BeanA对象,然后调用三级缓存中的lambda表达式**创建出BeanA的基本对象**,如果BeanA的有动态代理的相关操作,会在此时进行完毕,确保此时BeanB注入的BeanA属性对象是**代理对象**而不是原始对象
  7. 在调用lambda函数创建完毕对象后,会将**BeanA**加入到**二级缓存**中,并且会删除**三级缓存**的内容
  8. 此时BeanB会继续执行后续的操作,然后放到**一级缓存**中,此时**BeanB初始化完成**
  9. 会到BeanA的初始化流程中,从**一级缓存**中获取到**BeanB**的对象,并且此时BeanB的对象也是已经完成动态代理操作的。
  10. 在属性注入完毕后,**earlyProxyReferences**需要判断是否需要创建动态代理对象,因为此时BeanB的初始化流程中已经生成了BeanA对应的代理对象,此时不需要再创建
  11. 在初始化创建完毕后,BeanA也会放到单例池中

为什么一定要使用三级缓存

  1. 在只有二级缓存的情况下,无法处理需要创建代理对象的操作
  2. 在BeanA中包含BeanB属性时,要注入BeanB对象**不能只是注入BeanB的基本对象****需要**注入的是BeanB的**代理对象**
  3. 但是此时BeanB没有**走完初始化的流程**,不能在此时直接创建BeanB的代理对象,因为**不能够创建多个代理对象**,要保证BeanB的单例
  4. 因此需要引入现在的 **earlySingletonObjects**二级缓存用来解决循环依赖中,没有进行完毕初始化流程,但是**需要提前将Bean暴露给其他Bean进行使用**的情况

Spring可以解决哪些循环依赖

单例Bean,并且通过@Autowire等通过setter方法注入的普通AOP增强Bean(可以解决循环依赖)

原型模式Bean,不会保存在单例池中,因此无法使用三级缓存(不能解决)

构造方法注入的Bean(不能解决)
  1. 在通过三级缓存解决循环依赖问题时,需要能够创建初始对象
  2. 但如果构造方法注入Bean的情况出现循环依赖,此时无法创建出初始对象
  3. 因此构造方法注入的Bean不能解决
@Async增强的Bean(不能解决)
  1. 普通的 AOP 代理都是通过 **AbstractAutoProxyCreator** 来生成代理类的,**AbstractAutoProxyCreator** 实现了 **SmartInstantiationAwareBeanPostProcessor**
  2. 而 @Async 标记的类是通过 **AbstractAdvisingBeanPostProcessor** 来生成代理的,**AbstractAdvisingBeanPostProcessor** 没有实现 **SmartInstantiationAwareBeanPostProcessor**
  3. 因此@Async 的类在发现循环依赖后,不会提前创建代理对象,此时其他的类则无法从二级缓存中获取到代理对象,因此无法解决循环依赖

@Lazy解决循环依赖的原理

@Lazy可以解决哪些循环依赖
  1. 构造方法的循环依赖
  2. @Async竹节标记的循环依赖
  3. 依旧不能解决原型模式的循环依赖
@Lazy如何解决循环依赖
  1. 在没有@Lazy时,此时会直接寻找依赖的对象,此时因为循环依赖,因此无法找到依赖的对象从而导致出错
  2. 在有@Lazy时,此时不会去直接寻找依赖的对象,会直接创建一个代理对象,作为构造方法的参数进行传入
  3. 此时在Bean真正调用该Bean的方法时,实际调用的是对应代理对象的方法,代理对象会先在单例池中寻找该Bean,然后再调用该Bean的对应方法,从而解决循环依赖

Aware相关接口

Aware接口执行顺序

名称用途所属容器回调点
BeanNameAware获取bean名称BeanFactoryBean后处理器的BeforeInitialization方法之前
BeanClassLoaderAware获取bean的类加载器BeanFactoryBean后处理器的BeforeInitialization方法之前
BeanFactoryAware获取bean工厂(建议用下面的ApplicationContextAware)BeanFactoryBean后处理器的BeforeInitialization方法之前
EnvironmentAware获取环境相关信息,如属性、配置信息等ApplicationContextBean后处理器的BeforeInitialization方法中
EmbeddedValueResolverAware获取值解析器ApplicationContextBean后处理器的BeforeInitialization方法中
ResourceLoaderAware获取资源加载器ApplicationContextBean后处理器的BeforeInitialization方法中
ApplicationEventPublisherAware获取事件广播器,发布事件使用ApplicationContextBean后处理器的BeforeInitialization方法中
MessageSourceAware获取消息资源ApplicationContextBean后处理器的BeforeInitialization方法中
ApplicationContextAware获取ApplicationContextApplicationContextBean后处理器的BeforeInitialization方法中

Aware接口实际运用

  • Aware接口的主要作用是可以**提前获取到相对应的信息**,如果在某个Bean中需要使用某个对象,只需要让其实现 xxxAware接口,就可以获取到对应的对象
  • 在Aware处可以获取到Bean的相关信息,可以进行数据的处理,例如可以对Bean内属性进行赋值操作等。
  • 封装**ApplicationContextHolder** 上下文工具类,在封装的**工具类**或者是**封装的starter组件**中,无法直接使用ApplicationContext进行使用,此时则需要封装上下文工具类。

BeanPostProcess前置(postProcessBeforeInitialization)

  1. 在Aware相关接口执行完毕后,则马上执行BeanPostProcessor的相关方法
  2. BeanPostProcess是AOP实现的关键
public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

初始化方法

  1. **@PostConstruct** 所有对象实例化完成后调用
  2. 继承了**InitializingBean**接口 调用afterPropertiesSet()方法
  3. **Init-Method** @PostConstruct @Bean(init-method=…)

BeanPostProcess后置

正常使用

Disposable的Destory方法

  • @PreDestory
  • DisposableBean的destory()方法
  • 配置的destory-method
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值