Spring Bean生命周期&Hook&循环依赖 - ambition0802/spring-practice GitHub Wiki

集合的函数式编程支持

image-20201130193908040

实际上一般Context也同时是BeanDefinitionRegistry

AbstractApplicationContext implements BeanDefinitionRegistry

如何告别烦人的手动校验参数防止NEP

javax.annotation.Nonnull

@Primary

自动注入接口A是,A存在多个实现类,则被@Primary注解的实现类的优先级最高

内嵌Tomcat是如何启动的
各种类型的BeanDefinition的区别

RootBeanDefinition ChildBeanDefinition ParentBeanDefinition

FactoryBean
ImportBeanDefinitionRegistrar
⭐⭐⭐⭐⭐启动过程中的包扫描

springboot项目启动的时候,是如何将项目中用户自己设置的@component等自定义的bean扫瞄进容器的。

springboot, 如果没有配置scanner要扫描的包路径,默认是扫描springboot启动类所在的包,实现过程如下:

检查scanningPackages:

  1. Spring SPI机制加载ApplicationContextInitializer,加载了ConfigurationWarningsApplicationInitializer.
  2. ConfigurationWarningsApplicationInitializer执行initialize方法,在AbstractApplicationContext的beanFactoryPostProcessors(List)上放入了ConfigurationWarningsPostProcessor.
  3. 在AbstractApplicationContext的invokeBeanFactoryPostProcessors方法中,执行ConfigurationWarningsPostProcessor的postProcessBeanDefinitionRegistry方法,在方法中,获取BeanFactory中已经存在的AnnotationBeanDefinition(启动类的BeanDefinition就是一个AnnotationBeanDefinition),在AnnotationBeanDefinition上获取@ComponentScan注解的配置,从注解的配置中获取Scaner要扫描的packages,如果没有的话,将Springboot启动类的package添加到packages中。
  4. 检查packages是否异常。

扫描指定的scanningPackages:

  1. invokeBeanFactoryPostProcessors方法中执行BeanFactoryPostProcessor

  2. 执行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法。

  3. 先从BeanDefinitionRegistry中获取所有的BeanDefinition,从这些BeanDefiniton中捞出来被@Configuration注解了的,下文以CBD代指。

  4. 使用ConfigurationClassParser来解析所有的CBD.

  5. ConfigurationClassParser的processConfigurationClass方法从CBD开始递归解析CBD以及被CBD引入的bean(引入方式由多种:@Component、@PropertySource、@ComponentScans、@ComponentScan、@Import、@ImportResource、@Bean)

    protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
    		......
    		......
    		......
    		do {
    			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
    		}
    		while (sourceClass != null);
    
    		this.configurationClasses.put(configClass, configClass);
    	}
  6. ConfigurationClassParser的doProcessConfigurationClass方法来解析每个CBD。解析CBD上面的以下注解:@Component、@PropertySource、@ComponentScans、@ComponentScan、@Import、@ImportResource、@Bean(方法、设置是interface中被@Bean注解的default方法,我直呼牛逼)

  7. "Springboot启动过程中如何扫描指定的package并加载package下配置的bean"的答案已经在6中说的很清楚了,通过ConfigurationClassParser读取@Component配置,扫描basePackages包路径(如果没有配置,默认扫描Springboot启动类所在的package)下的配置的Spring bean(包括@Controller、@Service、@Configuration等等),扫描到这些bean之后,再调用ConfigurationClassParser的doProcessConfigurationClass方法进行递归扫描。

几个问题:

  1. ConfigurationClassPostProcessor 单例 是在什么时候被放到BeanFactory中的? -----> new AnnotationConfigServletWebServerApplicationContext()
⭐⭐⭐⭐⭐获取bean时解决循环依赖:三级缓存

问题:

  1. MergedBeanDefinition到底是什么鸡巴东西。。。
  2. InstantiationAwareBeanPostProcessor
  3. MergedBeanDefinitionPostProcessor
  4. InstantiationAwareBeanPostProcessor
  5. AutowiredAnnotationBeanPostProcessor
⭐⭐⭐⭐⭐Bean的所有HOOK

不只postprocessor,还有ImportBeanDefinitionRegistrar、各种interface等。

⭐⭐⭐⭐⭐Bean的所有HOOK循坏依赖&三级缓存 调用栈中的关键点

获取a的单例入口 -> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) L207

先去三级缓存里找a(这个方法典中典要说明下) -> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) L180

三级缓存中都没有a,去实例化a -->

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance L1164

实例化完之后在初始化之前按加入三级缓存中 -> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory L154

初始化a -> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean L1367

自动注入a当中的b property ,获取b的触发入口在 --> org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate L273

获取b的单例入口 , 有没有发现又调用回来这个方法了 -> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) L207

先去三级缓存里找b(这个方法典中典要说明下) -> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) L180

三级缓存中都没有b,去实例化b -->

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance L1164

实例化完之后在初始化之前加入三级缓存中 -> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory L154 初始化b -> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean L1367 自动注入b当中的a property ,获取a的触发入口在 --> org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate L273

获取a的单例入口 -> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) L207

先去三级缓存里找a(这个方法典中典要说明下) -> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) L180

按照1-2-3的顺序,从三个级别的缓存中找a,最终在三级缓存中找到a,执行ObjectFactory.getObject(AOP逻辑)来获取a的实例。将a从三级缓存中移动到二级缓存,因为已经执行过”aop逻辑了“

b只有a一个property,设置完之后,再执行其他一些逻辑,比如BeanPostProcessor等逻辑,最终完成初始化。 -> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) L1767

b最终完成了初始化之后,如果开启了AOP,则在执行BeanPostProcessor的postProcessAfterInitialization

时候,会执行AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization,这里面就是创建目标bean的代理对象,来完成aop(代理方式有JDK和CGLIB)

bean完成初始化之后就是一个完整的bean了。如果需要生成代理,在这个时候也早执行过BeanFactoyPostprocessor的postProcessAfterInitialization方法了,早就包装了一层代理对象了,所以直接从三级缓存中移除并添加到一级缓存中,不需要再执行三级缓存中的工厂方法来生成代理了。 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton L137

最后b从三级缓存中拿出来放到一级缓存中, org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton L137

实际上两级缓存就能解决循环依赖的问题。为什么要设置第三级缓存?

spring的aop还有@Transactional的实现原理,其实都是在原本的目标bean对象上,进行代理,封装一层。所以实际上我们的bean在实例化+初始化之后,如果有上述等类似的配置,spring会通过BeanPostProcessor的postProcessAfterInitialzation方法,来对我们的bean进行动态代理来实现功能加强。

但是如果没有第三级缓存,当我们需要动态代理的bean存在循环依赖的话,在初始化后再动态代理我们的bean,就太晚了。举个例子,A需要动态代理,A实例化完之后,依赖B,初始化的时候注入B,创建B实例,B依赖A,B进行初始化的时候注入实例化完但为初始化也未被动态代理的A,B初始化完毕,A初始化完毕,A进行动态代理。

执行完上述这个例子的过程之后,我们可以发现,如果没有第三级缓存,B中持有的A的对象并不是A经过动态代理之后的对象,那么AOP、Transactional等功能就是失效没用的。

所以我们需要有一个Map,来保存已经实例化完且未初始化也未动态代理过的对象。当存在循环依赖的时候,就从这个Map中将对象拿出来,也尝试动态代理一下,再将对象返回。这个Map就是我们的第三级缓存。

提一嘴 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#earlyProxyReferences记录了从第三级缓存中去除提前被aop动态包装了的循环依赖,防止同一个对象进行重复的动态代理。

⭐BEAN生命周期中的hook以及顺序定义在BeanFactory接口上

⚠️ **GitHub.com Fallback** ⚠️