Spring IOC主要分为两个大的部分,一部分是IOC容器的启动,另一部分是getBean
getBean的部分我盗个图
图一来自https://juejin.im/post/5dec9fe76fb9a01608236cd3
1.实例化 Instantiation (上图中的createBeanInstance:利用构造方法等途径new出实例)
2.属性赋值 Populate (上图中的populateBean:往实例中注入各个属性)
3.初始化 Initialization (上图中的initializeBean:对实例进行一些后续初始化工作)
4.销毁 Destruction
而在这1.2.3.件事的前后都有很多postProcessor和Aware可对bean做扩展
利用BeanPostProcessor中的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
(如果有代理对象返回则直接调用每个BeanPostProcessor.postProcessAfterInitialization返回了,不需要调用后面的doCreateBean实例化了)
AbstractAutoProxyCreator就是一个InstantiationAwareBeanPostProcessor,它在这里会被调用
从该阶段开始到结束,这些逻辑都在doCreateBean方法中
通过determineCandidateConstructors确定构造方法
如果没有则使用无参构造方法
如果有工厂方法,则使用构造方法或工厂方法创建bean
instantiateUsingFactoryMethod(beanName, mbd, args);
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
1.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(允许用户在Bean注入属性前改变BeanDefinition的信息)
2.autowireByName或者autowireByType (用于在配置文件中通过
配置的属性并且显示在配置文件中配置了autowireMode属性) 3.InstantiationAwareBeanPostProcessor.postProcessPropertyValues ( @Autowire @Resource @Value @Inject 等注解的依赖注入过程,实际执行依赖注入逻辑的是AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues)
4.applyPropertyValues (注入配置文件中
配置的属性,早就不用XML配置文件来配置Bean的属性了)
注:InstantiationAwareBeanPostProcessor
接口至此三个方法都执行了
1.执行Aware 方法
invokeAwareMethods(beanName, bean);
这里面执行了
BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三个接口的实现方法
2.
调用每个BeanPostProcessor类的postProcessBeforeInitialization方法其中ApplicationContextAwareProcessor#postProcessBeforeInitialization会调用invokeAwareInterfaces方法它会调用这几种Aware的实现
EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
3.invokeInitMethods执行初始化方法
设置Bean的初始化方法有两种方法,一种是在xml或者@Bean指定init-method方法。另一种是让bean实现InitializingBean接口重写afterPropertiesSet()方法。
此方法中的执行逻辑是:
先执行InitializingBean接口的afterPropertiesSet方法,再进行init-method
4.调用每一个BeanPostProcessor的postProcessAfterInitialization方法
AbstractAutoProxyCreator就是一个BeanPostProcessor,它在这里会被调用
通过getSingleton(String,false),从一级或者二级缓存里取出已经暴露的实例
如果没有早期暴露过则返回实例
如果有早期暴露:
原实例未经postProcessAfterInitialization代理(即在早期暴露的时候已经被代理过),则用早期暴露的实例返回
否则经过postProcessAfterInitialization代理,且被其他实例所依赖,即存在多个动态代理的循环依赖(如@Transactional和@Async一起使用),则抛出异常
扩展点图
可以看到扩展主要用到两个大类的接口:
1.BeanPostProcessor 作用于实例化、初始化阶段的前后。实现了这些接口的Bean会切入到多个Bean的生命周期中,例如自动注入以及AOP的实现都和他们有关
2.Aware,所有的Aware方法都是在初始化方法之前被调用完
Spring中提供了若干个BeanPostProcessor接口(下称BPP),BPP提供了在不同的时间点让用户对bean进行自定义调整的机会,大多数都在图一用黄色泡泡特别标示了,有以下几种BPP接口比较常用:
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation:实例化前的操作
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition:可对BeanDefinition添加额外的自定义配置
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation:在populateBean前用户可以手动注入一些属性
InstantiationAwareBeanPostProcessor#postProcessPropertyValues:对属性进行注入,例如配置文件加密信息在此解密后注入
BeanPostProcessor#postProcessBeforeInitialization:属性注入后的一些额外操作
BeanPostProcessor#postProcessAfterInitialization:实例完成创建的最后一步,这里也是一些BPP进行代理的时机
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference:返回早期暴露的bean引用,一个典型的例子是循环依赖时如果有动态代理,需要在此先返回代理实例
只调用一次的接口
又可以分为两类:
Aware类型的接口
生命周期接口
作用就是让我们能够拿到Spring容器中的一些资源。
Aware之前的名字就是可以拿到什么资源,例如BeanNameAware
可以拿到BeanName。
调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
Aware接口具体可以分为两组
Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware 实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口
可以看到并不是所有的Aware接口都使用同样的方式调用。
Bean××Aware都是在代码中直接调用的,
而ApplicationContext相关的Aware都是通过BeanPostProcessor类的ApplicationContextAwareProcessor#postProcessBeforeInitialization()实现的。
至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
1.InitializingBean接口的afterPropertiesSet方法
对应生命周期的初始化阶段,在源码的
invokeInitMethods(beanName, wrappedBean, mbd)
方法中调用。
有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
2.DisposableBean接口的destroy方法
类似于InitializingBean,对应生命周期的销毁阶段
以ConfigurableApplicationContext#close()方法作为入口,
实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。