四、bean实例化、依赖注入、缓存

目录

概述

1. bean实例化入口

2. 创建bean实例

2.1 通过factoryMethod实例化

2.2 通过Autowired有参构造实例化

2.3 通过默认的无参构造获取bean实例

3. applyMergedBeanDefinitionPostProcessors收集属性和方法

3.1 CommonAnnotationBeanPostProcessor

3.1.1 收集@PostConstruct和@PreDestroy修饰的方法

3.1.2 收集@Resource修饰的属性和方法

3.2 AutowiredAnnotationBeanPostProcessor

4. 包装bean实例加入singletonFactories缓存

5. populateBean di属性注入和方法调用

5.1 CommonAnnotationBeanPostProcessor处理@Resource注解

5.2 AutowiredAnnotationBeanPostProcessor处理@Value@Autowired注解

5.2.1 @Value、@Autowired属性注入

5.2.2 @Autowired方法调用

5.3 ConfigurationClassPostProcessor为$$beanFactory属性注入beanFactory实例

6. initializeBean初始化调用

6.1 如果bean实现了aware接口,调用相关接口

6.2 调用@PostConstruct修饰的方法

6.3 invokeInitMethods调用afterPropertiesSet方法、initMethod方法

6.4 生成AOP代理

7. 收集注册disposableBeans

7.1 收集有销毁方法的bean加入disposableBeans容器

7.2 bean销毁方法的调用

8.bean完成初始化后加入singletonObjects缓存

9. FactoryBean

​10.@Configuration CGLIB代理bean

10.1 生成@Configuration对应的CGLIB增强class

10.2 增强setBeanFactory方法

10.3 增强@Bean修饰的方法

11. 总结bean的初始化和缓存

12. getBean缓存总结


(本片中用到的演示项目地址:https://gitee.com/yejuan/spring-learning-no-xml 对应tag: spring-c4)

概述

         下面是本篇中一些重要的知识点

  1. bean实例化是遍历BeanFactory中的beanNames,对于beanDefinition为非抽象、单例、非懒加载的才调用getBean方法进行实例化;
  2. @Bean对应的bean的实例通过调用factoryMethod创建;
  3. 获取bean实例的方式按照先factoryMethod、再@Autowired修饰的构造器、再有参构造器、最后默认无参构造器的顺序进行
  4. 如果@Bean修饰的方法有参数或者bean的构造方法中有参数,会触发getBean获取获取参数实例;
  5. 在AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors中进行筛选有@Autowired修饰的构造器;
  6. applyMergedBeanDefinitionPostProcessors方法中会进行@PostConstruct、@PreDestory修饰的方法和需要依赖注入的属性和方法的收集;
  7. CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition中收集@PostConstruct、@PreDestory修饰的方法和@Resource修饰的属性和方法;
  8. AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition中收集@Autowired、@Value修饰的属性和方法;
  9. DefaultListableBeanFactory中的singletonFactories容器缓存已实例化但还未进行初始化方法调用和依赖注入的bean实例的Lambda表达式包装对象,该Lambda表达式包装了SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference的接口调用;
  10. singletonFactories缓存是循环依赖得以实现的支持;
  11. @Configuration修饰的beanClass会在ConfigurationClassPostProcessor#postProcessBeanFactory方法中进行CGLIB增强,得到的是代理bean,代理bean对setBeanFactory方法和@Bean修饰的方法进行了增强;
  12. 完全初始化完成的bean放在singletonObjects容器,实现了FactoryBean接口的bean会通过getObject创建bean,getObject创建的bean放在factoryBeanObjectCache容器。

1. bean实例化入口

遍历spring容器中的beanDefinition进行bean实例化

org.springframework.context.support.AbstractApplicationContext#refresh

beanDefinition为非抽象、单例、非懒加载的调用getBean实例化

2. 创建bean实例

先从Map<String, Object> singletonObjects缓存容器中取,取到了直接返回,没取到创建实例。创建实例前把beanName加入Set<String> singletonsCurrentlyInCreation容器,调用Lambda表达式进行实例创建。

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

创建实例

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

2.1 通过factoryMethod实例化

上篇讲到扫描到@Bean修饰的方法会创建BeanDefinition,设置了beanDefinition的factoryMethodName和factoryBeanName。

容器的refresh方法中的invokeBeanFactoryPostProcessors会调用到AbstractBeanFactory#isFactoryBean,从该方法进入又会调到AbstractAutowireCapableBeanFactory#getTypeForFactoryMethod。通过这个方法会为@Bean对应的beanDefiniton设置factoryMethodToIntrospect,factoryMethodToIntrospect即为factroyMethodName对应的方法,以便后续通过factoryMethodToIntrospect实例化。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getTypeForFactoryMethod

获取factoryBean实例
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod

如果factoryMethod方法有参数,调用getBean从容器中获取实例设置到参数中。
org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod

从容器中获取参数类型的beanNames,找到匹配的bean

从容器中获取实例
org.springframework.beans.factory.support.DefaultListableBeanFactory#addCandidateEntry

有方法对象,有方法所属类对应实例和参数就可以进行方法调用了,返回值就是该beanDefinition所对应的bean实例。
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate

2.2 通过Autowired有参构造实例化

通过AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors获取到bean的有@Autowired修饰的构造器

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

收集有@Autowired修饰的构造器

解析构造器中的参数,调用getBean获取参数实例,又调到了2.1中分析过的createArgumentArray方法。
org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor

有了构造器、参数,通过反射获取bean实例。

2.3 通过默认的无参构造获取bean实例

咱们用得最多的也就是通过默认的无参构造获取bean实例。

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

反射创建bean实例

3. applyMergedBeanDefinitionPostProcessors收集属性和方法

bean实例创建后接下就要通过applyMergedBeanDefinitionPostProcessors方法调用到CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法进行@PostConstruct和@PreDestroy修饰的方法、@Resource修饰的属性和方法、@Autowired和@Value修饰的属性和方法的收集。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

3.1 CommonAnnotationBeanPostProcessor

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

3.1.1 收集@PostConstruct和@PreDestroy修饰的方法

CommonAnnotationBeanPostProcessor创建的时候设置了初始化注解PostConstruct和销毁PreDestory注解类型

扫描收集@PostConstruct、@PreDestory修饰的方法

org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata

@PostConstruct、@PreDestory修饰的方法需要为无参方法

将收集的初始化、销毁方法加入容器

3.1.2 收集@Resource修饰的属性和方法

需要注意的是@Resource修饰的方法必须满足有且只有一个参数

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#findResourceMetadata

3.2 AutowiredAnnotationBeanPostProcessor

扫描收集@Autowired和@Value修饰的属性和方法。

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

AutowiredAnnotationBeanPostProcessor创建的时候设置了扫描类型为Autowired、Value注解。

扫描收集属性、扫描收集方法递归处理父类

4. 包装bean实例加入singletonFactories缓存

2、3中完成了bean实例的创建和一些方法与属性的收集,接下来默认情况下会把创建好的实例包装到循环调用SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法的Lambda表达式中,然后缓存到singletonFactories容器中,singletonFactories缓存支持了循环依赖的实现。

循环调用SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference方法,此处买点可对bean再进行一些处理

加入singletonObjects缓存

5. populateBean di属性注入和方法调用

前面讲到applyMergedBeanDefinitionPostProcessors中对@Resource、@Value、@Autowired修饰的属性和方法进行收集,现在populateBean方法中通过CommonAnnotationBeanPostProcesso、 AutowiredAnnotationBeanPostProcessor的postProcessProperties接口支持对收集到的属性进行设置、收集到的方法进行调用。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

5.1 CommonAnnotationBeanPostProcessor处理@Resource注解

CommonAnnotationBeanPostProcessor#postProcessProperties中完成了对@Resource修饰的属性的注入和@Resource修饰的方法参数注入和调用

对于@Resource修饰的参数调用getBean获取实例,对于@Resource修饰的方法先进行参数注入后再反射调用

5.2 AutowiredAnnotationBeanPostProcessor处理@Value@Autowired注解

5.2.1 @Value、@Autowired属性注入

上一篇我们讲到ConfigurationClassPostProcessor#processConfigBeanDefinitions会将通过@PropertySource导入的配置文件加载到environment的资源属性中,我们通过类似@Value("${account.name}")这样的表达式就可以获取配置的值,@Value属于注入正是基于这个原理,@Autowired会触发getBean获取需要注入的属性实例,同之前@Bean方法的参数注入是一样的。

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

获取@Value注解中配置的key,如 @Value("${account.name}")将获取到account.name,跟据获取到的key从environment的属性资源中获取配置的value

遍历属性资源容器propertySources调用getProperty(key)获取值
org.springframework.core.env.PropertySourcesPropertyResolver#getProperty

获取到属性值之后通过反射设置属性

5.2.2 @Autowired方法调用

         @Autowired修饰的方法如果有参数会先通过5.2.1同样的方式获取参数,然后再进行反射调用方法。

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject

5.3 ConfigurationClassPostProcessor为$$beanFactory属性注入beanFactory实例

                   spring会为所有@Configuration修饰的bean通过CGLIB进行增强生成代理实例,代理实例中有$$beanFactory属性,依赖注入时会通过ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor#postProcessProperties为$$beanFactory属性赋值。@Configuration CGLIB增强bean会单独详细分析。

6. initializeBean初始化调用

6.1 如果bean实现了aware接口,调用相关接口

BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口调用

1.ApplicationContextAwareProcessor#postProcessBeforeInitialization:
              EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、
              ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware 接口调用;
2.ServletContextAwareProcessor#postProcessBeforeInitialization:
              ServletContextAware、ServletConfigAware接口调用
3.ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor#postProcessBeforeInitialization
               ImportAware接口调用


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

6.2 调用@PostConstruct修饰的方法

         3中讲到CommonAnnotationBeanPostProcessor对bean中@PostConstruct修饰的方法进行了收集,现在对上面收集到的方法进行调用。

InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization

6.3 invokeInitMethods调用afterPropertiesSet方法、initMethod方法

如果bean有实现InitializingBean接口调用bean的afterPropertiesSet方法,调用initMethod方法(可在<bean>标签中配置)

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods

6.4 生成AOP代理

applyBeanPostProcessorsAfterInitialization是生成AOP代理的入口,这里只简单提下,关于AOP后面会单独详细分析,如果bean匹配到advisor则会生成代理。

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

7. 收集注册disposableBeans

7.1 收集有销毁方法的bean加入disposableBeans容器

如果bean有实现DisposableBean 、AutoCloseable接口或者有自定义的destroyMethod方法(通过<bean>标签可配置)或者有@PreDestory修饰的方法,将bean包装到DisposableBeanAdapter对象中加入DefaultSingletonBeanRegistry中的Map<String, Object> disposableBeans容器,当web服务器停止时会通过Listener调用到bean的销毁方法。通过bean的销毁方法我们可以做一些资源释放等的收尾工作。

判读是否有实现DisposableBean 、AutoCloseable接口或者有配置destroyMethod

通过CommonAnnotationBeanPostProcessor.requiresDestruction过滤有@Predestory方法的bean

DisposableBeanAdapter#hasApplicableProcessors

加入disposableBeans容器

7.2 bean销毁方法的调用

        bean销毁方法的调用不属于bean实例化、di注入流程中的内容,上面讲到了销毁方法的收集顺带就理一下销毁方法的调用。当web服务器stop的时候会调用到ServletContextListenercontextDestroyed方法。ContextLoaderListener#contextDestroyed方法就会触发bean销毁方法的调用。

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingletons

通过CommonAnnotationBeanPostProcessor.postProcessBeforeDestruction反射调用@PreDestory修饰的方法,调用DisposableBean的destroy方法,调用自定义的销毁方法

8.bean完成初始化后加入singletonObjects缓存

到上面的第7节为止已经完成了bean的创建、依赖注入、初始化方法调用等一系列工作,bean已经可以进行业务调用了。接下来我们把初始化完成后的bean缓存起来,以便能够通过getBean灵活获取。

bean已完全初始化,将beanName从正在创建的容器singletonsCurrentlyInCreation中移除

bean已完全初始化,将bean加入singletonObjects容器,并从中间状态容器singletonFactories、earlySingletonObjects容器中移除。

9. FactoryBean

如果bean实现了FactoryBean接口会将getObject方法的结果缓存到DefaultListableBeanFactoryMap<String, Object> factoryBeanObjectCache容器中,如下示:factoryBeanObjectCache容器中缓存的myFacotryBean-> UserBean实例的映射关系,singletonObjects缓存的myFacotryBean-> MyFacotryBean实例的映射关系。getObject方法返回的UserBean实例也可以通过@Autowired等进行自动装配。要从spring容器中获取UserBean实例通过getBean(“myFacotryBean”)如果要获取MyFacotryBean实例通过getBean(“&myFacotryBean”)
@Component
public class MyFacotryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new UserBean();
    }

    @Override
    public Class<?> getObjectType() {
        return UserBean.class;
    }
}

 

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

10.@Configuration CGLIB代理bean

10.1 生成@Configuration对应的CGLIB增强class

ConfigurationClassPostProcessor#postProcessBeanFactory方法中会遍历所有有@Configuration修饰的bean,将其对应的beanClass设置为CGLIB增强后的class。

增强的class实现了EnhancedConfiguration接口,添加了$$beanFactory属性,$$beanFactory的类型为BeanFactory,并对setBeanFactory方法和@Bean修饰的方法进行了增强。

org.springframework.context.annotation.ConfigurationClassEnhancer#newEnhancer

10.2 增强setBeanFactory方法

增强setBeanFactory方法为$$beanFactory属性设置BeanFactory实例。获取属性对象,通过反射赋值。

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor#intercept

10.3 增强@Bean修饰的方法

只有首次调用时才真正进行方法调用,后续从beanFactory中获取缓存实例。如果@Bean方法的返回对象是factoryBean实例,对返回对象再次进行CGLIB代理,对getObject方法进行增强,调用beanFactory.getBean获取实例。

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor

org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#createCglibProxyForFactoryBean

11. 总结bean的初始化和缓存

12. getBean缓存总结

  1. 如果singletonObjects中有缓存从singletonObjects中获取;
  2. 如果singletonObjects中没有从earlySingletonObjects中获取;
  3. 如果earlySingletonObjects中没有从singletonFactories中获取,
  4. 如果singletonFactories中有获取到将singletonFactories中缓存的对应ObjectFactory移除,将获取到的实例加入earlySingletonObjects缓存;
  5. 如果singletonFactories中也没有通过BeanDefinition进行bean的实例化、初始化,完全初始化的bean最终会放在singletonObjects中缓存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值