一、Bean生命周期
Spring中的一个Bean从生到灭要经历很多过程,总体分为Bean定义、实例化、属性赋值(依赖注入)、初始化、生存期、销毁几个阶段:
BeanPostProcessor
接口可以对Bean生命周期中的很多部分进行扩展,并且Spring容器中有很多内建的 BeanPostProcessor
对Spring Bean的功能进行支持。BeanPostProcessor
不仅在IOC上发挥了重要作用,在AOP上也发挥了重要的作用。搞懂了Spring内置的BeanPostProcessor的功能,基本上就把Spring Bean的生命周期搞懂了。
Spring Bean的生命周期上面图二已经展示,可以主要分为如下4个部分:
(1)处理BeanDefinition
:BeanDefinition
的解析,注册,合并
(2)Bean实例化(Instantiation
):调用构造函数,生成对象
(3) Bean属性赋值:查找被@Autowired
和@Value
标注的方法或属性,注入需要的值
(4)Bean Aware 接口回调
(4)Bean初始化(Initialization
):已经生成bean,进行属性赋值
(5)Bean销毁:并没有gc
实例化和初始化的区别
实例化:实例化前 Bean 对象未创建,实例化作用是创建 Bean 对象
初始化:初始化前 Bean 对象已创建,初始化的作用是对 Bean 的属性进行赋值
详细流程
1、Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
2、依赖注入Bean的属性
3、如果bean实现BeanNameAware
接口,则工厂通过传递bean的ID来调用setBeanName()
4、如果bean实现BeanFactoryAware
接口,工厂通过传递自身的实例来调用setBeanFactory()
,将BeanFactory容器实例传入
5、如果 Bean 实现了 ApplicationContextAware
接口,则 Spring 调用 setApplicationContext()
方法传入当前 ApplicationContext 实例的引用。
6、如果Bean实现了BeanPostProcessor
接口,将调用postProcessBeforeInitialization()
方法。
7、如果Bean 实现了InitializingBean
接口,Spring将调用他们的afterPropertiesSet()
方法。
8、如果bean使用 init-method
声明了初始化方法,该方法也会被调用
9、如果Bean 实现了BeanPostProcessor
接口,调用postProcessAfterInitialization()
方法。
10、此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。如果在 <bean>
中指定了该 Bean 的作用范围为 scope=”singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean>
中指定了该 Bean 的作用范围为 scope=”prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
11、如果bean实现了DisposableBean
接口,Spring将调用它的destory()
接口方法。
12、如果bean使用了 destory-method
声明销毁方法,该方法也会被调用。
Bean 完整的生命周期
文字解释如下:
————————————初始化————————————
- BeanNameAware.setBeanName() 在创建此bean的bean工厂中设置bean的名称,在普通属性设置之后调用,在InitializinngBean.afterPropertiesSet()方法之前调用
BeanClassLoaderAware.setBeanClassLoader()
: 在普通属性设置之后,InitializingBean.afterPropertiesSet()之前调用- BeanFactoryAware.setBeanFactory() : 回调提供了自己的bean实例工厂,在普通属性设置之后,在InitializingBean.afterPropertiesSet()或者自定义初始化方法之前调用
EnvironmentAware.setEnvironment()
: 设置environment在组件使用时调用EmbeddedValueResolverAware.setEmbeddedValueResolver()
: 设置StringValueResolver 用来解决嵌入式的值域问题ResourceLoaderAware.setResourceLoader()
: 在普通bean对象之后调用,在afterPropertiesSet 或者自定义的init-method 之前调用,在 ApplicationContextAware 之前调用。ApplicationEventPublisherAware.setApplicationEventPublisher()
: 在普通bean属性之后调用,在初始化调用afterPropertiesSet 或者自定义初始化方法之前调用。在 ApplicationContextAware 之前调用。MessageSourceAware.setMessageSource()
: 在普通bean属性之后调用,在初始化调用afterPropertiesSet 或者自定义初始化方法之前调用,在 ApplicationContextAware 之前调用。ApplicationContextAware.setApplicationContext()
: 在普通Bean对象生成之后调用,在InitializingBean.afterPropertiesSet
之前调用或者用户自定义初始化方法之前。ServletContextAware.setServletContext()
: 运行时设置ServletContext,在普通bean初始化后调用,在InitializingBean.afterPropertiesSet之前调用,在 ApplicationContextAware 之后调用注:是在WebApplicationContext 运行时- BeanPostProcessor.postProcessBeforeInitialization() : 将此BeanPostProcessor 应用于给定的新bean实例 在任何bean初始化回调方法(像是InitializingBean.afterPropertiesSet或者自定义的初始化方法)之前调用。这个bean将要准备填充属性的值。返回的bean示例可能被普通对象包装,默认实现返回是一个bean。
- BeanPostProcessor.postProcessAfterInitialization() : 将此BeanPostProcessor 应用于给定的新bean实例 在任何bean初始化回调方法(像是InitializingBean.afterPropertiesSet或者自定义的初始化方法)之后调用。这个bean将要准备填充属性的值。返回的bean示例可能被普通对象包装
- InitializingBean.afterPropertiesSet(): 被BeanFactory在设置所有bean属性之后调用(并且满足BeanFactory 和 ApplicationContextAware)。
————————————销毁————————————
在BeanFactory 关闭的时候,Bean的生命周期会调用如下方法:
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction()
: 在销毁之前将此BeanPostProcessor 应用于给定的bean实例。能够调用自定义回调,像是DisposableBean 的销毁和自定义销毁方法,这个回调仅仅适用于工厂中的单例bean(包括内部bean)- 实现了自定义的destory()方法
2、简述流程
Spring中一个Bean的创建大概分为以下几个步骤
1.推断构造方法
2.实例化
3.填充属性,也就是依赖注入
4.处理Aware回调
5.初始化前,处理@PostConstruct注解
6.初始化,处理InitializingBean接囗
7.初始化后,进行AOP
二、Bean后处理器
1、BeanPostProcessor
首先这是一个接口,其中定义了两个方法,分别会在Bean初始化前,初始化后(实例化和依赖注入完毕后)这两个时机执行,对bean的生命周期进行扩展,这两个方法中已经可以拿到半成品bean对象,并且属性填充已经结束了,可以用来对bean中的一些属性进行校验或者重新赋值。
Bean后处理器的注册
ApplicationContext
可以在其bean定义中自动检测代码 BeanPostProcessor bean
,并将这些后处理器应用到随后创建的任何bean。普通的beanFactory
允许对后处理器进行编程注册,并将它们应用于通过bean工厂创建的所有bean
接口方法
通常,通过标记接口或类似方式填充bean的后处理器将实现 postProcessBeforeInitialization
,而使用代理包装bean的后处理器通常将实现postProcessAfterInitialization
初始化流程
- 检查容器中是否存在
BeanPostProcessor
,存在就调用postProcessBeforeInitialization
- 如果返回null(或者所有的BeanPostProcessor执行完毕),往下执行
- 执行bean的初始化方法
- 再次判断容器是否存在
BeanPostProcessor
,存在就调用postProcessAfterInitialization方法- 如果返回null(或者所有的BeanPostProcessor执行完毕)
- 运行结束
public interface BeanPostProcessor {
/**
* 在任何bean实例化前回调
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 在任何bean实例化后回调
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
2、自定义后处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Person){
System.out.println("postProcessBeforeInitialization执行" + beanName);
Person person = (Person) bean;
person.setId(1L);
person.setName("rewind");
return person;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization执行: "+beanName);
return null;
}
}
3、InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor
代表了Spring的另外一段生命周期:实例化和属性赋值。先区别一下Spring Bean的实例化和初始化两个阶段的主要作用:
1、实例化—-实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中
2、初始化—-初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性
InstantiationAwareBeanPostProcessor
接口继承BeanPostProcessor
接口,它内部提供了3个方法,再加上BeanPostProcessor
接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor
接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
postProcessBeforeInstantiation
方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization
方法会调用,其它方法不再调用;否则按照正常的流程走;比如用来解析@PostConstruct
、@ConfigurationProperties
postProcessAfterInstantiation
方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues
方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck()
);如果该方法返回false,并且不需要check,那么postProcessPropertyValues
就会被忽略不执行;如果返回true,postProcessPropertyValues
就会被执行postProcessPropertyValues
方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation
方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改postProcessProperties
:依赖注入阶段执行,比如解析 @Autowired、@Value- 父接口
BeanPostProcessor
的2个方法postProcessBeforeInitialization
和postProcessAfterInitialization
都是在目标对象被实例化之后,并且属性也被设置之后调用的
Instantiation
表示实例化:实例化的意思在对象还未生成
Initialization
表示初始化:初始化的意思在对象已经生成
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 在目标对象实例化之前调用
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 目标对象实例化之后调用
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
/**
* 依赖注入阶段执行,比如解析 @Autowired、@Value
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
/**
* 对属性值进行修改,在Spring后续版本中会被移除,使用上面的方法替代
*/
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
4、生命周期演示
@Component
public class Person {
private Long id;
private String name;
private Pet pet;
public Person(){
System.out.println("2、实例化阶段--构造方法执行");
}
@Autowired
public void autowired(Pet pet){
System.out.println("5、依赖注入阶段--@Autowired执行");
this.pet = pet;
}
@PostConstruct
public void init(){
System.out.println("7、初始化--@PostConstruct执行");
}
@PreDestroy
public void destory(){
System.out.println("10、销毁阶段--@PreDestroy执行");
}
}
自定义后处理器
@Component
public class MyBeanPostProcessor2 implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
/**
* 实例化前(即调用构造方法前)执行的方法
* 返回null保持原有对象不变,返回不为null,会替换掉原有对象
* 来自InstantiationAwareBeanPostProcessor
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("person")){
System.out.println("1、实例化阶段--实例化之前执行");
}
return null;
}
/**
* 实例化后执行的方法
* 这里如果返回 false 会跳过依赖注入阶段
* 来自InstantiationAwareBeanPostProcessor
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("person")) {
System.out.println("3、实例化阶段--实例化之后执行");
}
return true;
}
/**
* 依赖注入阶段执行的方法
* 比如解析 @Autowired、@Value
* 如果返回PropertyValues,跳过postProcessPropertyValues(将弃用)
* 如果返回null,将继续解析postProcessPropertyValues
* 来自InstantiationAwareBeanPostProcessor
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("person")){
System.out.println("4、属性赋值阶段--@Autowired、@Value");
}
return null;
}
/**
* 初始化之前执行
* 这里返回的对象会替换掉原本的 bean
* 如果返回null,不会继续调用后续的 BeanPostProcessors
* 案例如 @PostConstruct、@ConfigurationProperties
* 来自 BeanPostProcessor
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("person")){
System.out.println("6、初始化阶段--初始化之前执行,如@PostConstruct");
}
return bean;
}
/**
* 初始化之后执行
* 这里返回的对象会替换掉原本的 bean
* 如果返回null,不会继续调用后续的 BeanPostProcessors
* 案例如 代理增强
* 来自 BeanPostProcessor
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("person")){
System.out.println("8、初始化阶段--初始化之后执行,如代理增强");
}
return bean;
}
/**
* 销毁前执行的方法
* 来自DestructionAwareBeanPostProcessor
*/
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("person")){
System.out.println("9、销毁阶段--销毁前执行");
}
}
}
输出
1、实例化阶段--实例化之前执行
2、实例化阶段--构造方法执行
3、实例化阶段--实例化之后执行
4、属性赋值阶段--@Autowired、@Value
5、依赖注入阶段--@Autowired执行
6、初始化阶段--初始化之前执行,如@PostConstruct
7、初始化--@PostConstruct执行
8、初始化阶段--初始化之后执行,如代理增强
9、销毁阶段--销毁前执行
10、销毁阶段--@PreDestroy执行
5、@Autowired原理
(1)演示代码
@Autowired
注解实现自动注入的功能是通过 bean 的后置处理器 AutowiredAnnotationBeanPostProcessor
实现的。
下面是演示使用的 bean
@Data
@Component
public class Person {
private Long id;
private String name;
@Autowired
private Car car;
}
下面代码演示 AutowiredAnnotationBeanPostProcessor
的运行分析
// 创建 ioc 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 向容器中注册单例bean
beanFactory.registerSingleton("car", new Car());
// 用于获取 @Value 中的值
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// --------AutowiredAnnotationBeanPostProcessor 运行分析-----------
// 此处将该后置处理器分离出来,手动运行
// 1、查找哪些属性、方法添加了 @Autowired 注解,称之为 InjectionMetadata(注入元数据)
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
// 因为 @Autowired 需要根据成员变量的 类型去ioc容器中找到对应的 bean ,所以也必须提供给他 ioc 容器
processor.setBeanFactory(beanFactory);
Person person = new Person();
// 此时person中的 Autowired 未执行注入,Person(id=null, name=null, car=null)
System.out.println(person);
/* ----------------------主要方法---------------------------- */
// 执行依赖注入,@Autowired 、 @Value
// 第一个参数用于指定自动装配的参数,此处不需要则为 null
// 第二个参数是注入的 bean,第三个参数 bean 的名字
processor.postProcessProperties(null, person, "person");
/* --------------------------------------------------------- */
//此处已经执行 @Autowired 的注入,Person(id=null, name=null, car=Car(carNo=null))
System.out.println(person);
@Autowired
注解对应的后处理器是AutowiredAnnotationBeanPostProcessor
@Value
注解需要配合@Autowired
注解一起使用,所以也用到了AutowiredAnnotationBeanPostProcessor
后处理器,然后@Value
注解还需要再用到ContextAnnotationAutowireCandidateResolver
解析器,否则会报错;@Resource
、@PostConstruct
、@PreDestroy
注解对应的后处理器是CommonAnnotationBeanPostProcessor
;@ConfigurationProperties
注解对应的后处理器是ConfigurationPropertiesBindingPostProcessor
。
(2)属性注入源码
processor.postProcessProperties(null, person, "person");
该语句是 @Autowired
注入的关键语句,该方法是实现了InstantiationAwareBeanPostProcessor
接口, 在Spring生命周期中,该方法是在赋值阶段执行的,源码如下:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找所有加了 @Autowired 的属性
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 通过反射注入对应的属性
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
可以看出主要的方法有 findAutowiringMetadata()
和 metadata.inject();
,接下来将对这两个方法进行解析
(3)findAutowiringMetadata
该方法是AutowiredAnnotationBeanPostProcessor
中用于 查找所有加了 @Autowired
的属性
// 注入的元数据缓存
private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 获取 bean 的名称作为元数据缓存的 key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 使用双重检查锁,判断缓存是否存在这个 bean
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 构造InjectionMetadata
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
接下来我们先来看看 InjectionMetadata
是什么?
InjectionMetadata
是用于管理注入元数据的内部类。不打算直接用于应用程序。
由 AutowiredAnnotationBeanPostProcessor
、org.springframework.context.annotationcommonannotationbeanpostprocessor
和org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
使用。
6、模板方法(设计模式)
代码中有动有静,在保证主业务代码不变的情况,可根据需求新增逻辑
public class TestMethodTemplatePattern {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造:" + bean);
System.out.println("依赖注入:" + bean);
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化:" + bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
processors.add(beanPostProcessor);
}
}
interface BeanPostProcessor {
void inject(Object bean);
}
}
三、工厂后处理器
1、介绍
BeanFactoryPostProcessor(工厂后处理器)
使用目的:在BeanFactory标准初始化之后调用,用来定制和修改BeanFactory的内容;主要是用来补充一些 BeanDifinition
定义
工作时机:所有的bean定义已经保存加载到beanFactory中,但bean的实例还没创建(详细的执执行时机源码见 Spring源码-ioc容器 文章);
加载 BeanDifinition —> 工厂后处理器执行 —> 添加 Bean 后处理器 —> 实例化 Bean
BeanFactoryPostProcessor
和 BeanPostProcessor
类似,可以对 beanDefinition
进行处理,也就是说 SpringIOC
容器允许 BeanFactoryPostProcessor
在容器实际实例化任何bean之前读取 beanDefinition
,并有可能修改他.并且我们还可以配置自定义的BeanFactoryPostProcessor
。如果想改变bean,那么使用beanPostProcessor
。
并通过order属性来控制 BeanFactoryPostProcessor
的执行次序.因为只有实现了Ordered接口时,才可以设置这个属性,所以在实现 BeanFactoryPostProcessor
的时候,就应该考虑实现Ordered接口。
BeanFactoryPostProcessor的作用域是容器级的,也就是说他只会对注册了他的那个容器生效。这里就关系到容器如何找到所有的 BeanFactoryPostProcessors
并执行他们的方法?
a)注解在Beanfactory中找到所有类型是
BeanFactoryPostProcessor
的组件,并执行他们的方法;b)在初始化创建其他组件前面执行;该方法是
invokeBeanFactoryPostProcessors(beanFactory);
,它在registerBeanPostProcessors(beanFactory)
和finishBeanFactoryInitialization(beanFactory)
方法前执行;
BeanFactoryPostProcessor源码
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
2、ConfigurationClassPostProcessor
该工厂后处理器使用来解析 @ComponentScan
,@Bean
,@Import
等注解标注的 bean 补充到工厂中
3、导致@Autowired失效
@Configuration
public class MyConfig {
@Autowired
private void setApplication(ApplicationContext application){
System.out.println("MyConfig -- @Autowired" + application);
}
@Bean
public BeanFactoryPostProcessor addBeanFactoryPostProcessor(){
return beanFactory -> System.out.println("MyBeanFactoryPostProcessor...");
}
}
在以上配置类中 @Autowired
注入失效,原因如下:
当配置类不包含
BeanFactoryPostProcessor
的情况下
这是一般 Bean 的生命周期
- 工厂后处理器执行 —> 注册 Bean 后处理器 —> 实例化 Bean —>
@Autowired
执行
当配置类包含
BeanFactoryPostProcessor
的情况下
因为工厂后处理器的执行是在 Bean 实例化之前执行,因此必须提前创建该配置类,而此时 Bean 还未实例化,后处理器也还没注册,所以导致 @Autowired
、@PostConstruct
等需要Bean后处理器的注解失效
此时该配置类的生命周期如下
- 配置类的创建和初始化,执行
Aware
和InitializingBean
- 执行工厂后处理器
- 注册 Bean 后处理器
解决方法
- 方法1、综上,在当配置类包含
BeanFactoryPostProcessor
的情况下,- 如果需要注入
ApplicationContext
,可通过ApplicationContextAware
。 - 如果需要在初始化时做一些事,可通过
InitializingBean
- 如果需要注入
- 方法2、可通过在方法上加 static 关键字解决
@Bean
public static BeanFactoryPostProcessor addBeanFactoryPostProcessor(){
return beanFactory -> System.out.println("MyBeanFactoryPostProcessor...");
}
四、Aware 系列接口
Aware 从字面意思理解就是“知道”、“感知”的意思,是用来获取 Spring 内部对象的接口。Aware 自身是一个顶级接口,它有一系列子接口,在一个 Bean 中实现这些子接口并重写里面的 set 方法后,Spring 容器启动时,就会回调该 set 方法,而相应的对象会通过方法参数传递进去。我们以其中的 ApplicationContextAware
接口为例。
(1)ApplicationContextAware
大部分 Aware 系列接口都有一个规律,它们以对象名称为前缀,获取的就是该对象,所以 ApplicationContextAware 获取的对象是 ApplicationContext 。
该回调方法的执行时机是在 Bean 依赖注入阶段之后,初始化之前
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
ApplicationContextAware 源码非常简单,其继承了 Aware 接口,并定义一个 set 方法,参数就是 ApplicationContext 对象,当然,其它系列的 Aware 接口也是类似的定义。其具体使用方式如下:
public class Test implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
在 Spring 启动过程中,会回调 setApplicationContext 方法,并传入 ApplicationContext 对象,之后就可对该对象进行操作。其它系列的 Aware 接口也是如此使用。具体的调用时机会在后面详细介绍。
以下是几种常用的 Aware 接口:
BeanNameAware
:获取 Bean 的名称。BeanFactoryAware
:获取 BeanFactory 对象,它是基础的容器接口。EnvironmentAware
:获取 Environment 对象,它表示整个的运行时环境,可以设置和获取配置属性。ApplicationEventPublisherAware
:获取 ApplicationEventPublisher 对象,它是用来发布事件的。ResourceLoaderAware
:获取 ResourceLoader 对象,它是获取资源的工具。
可能有个疑问,就是这些大部分明明能通过 @Autowired
注入来获取对应的对象,那为啥还需要这几个接口呢?因为 @Autowired
的实现需要通过后处理器实现,如果没加对应的后处理器的话,则无法获取(一般不会有这种情况),同时在下文介绍的@Autowired
失效情况中,也可用到这个;Aware 接口时 Spring 内置的回调手段,不会出现失效的情况,所以在很多源码中使用了这些接口。
ApplicationContextAware在源码中的使用案例
/**
* Spring Context 工具类
*
* @author Mark sunlightcs@gmail.com
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
(2)BeanNameAware
@Component
public class MyBean implements BeanNameAware {
/**
* 在创建bean时回调该方法,参数为bean的名称。
*/
@Override
public void setBeanName(String name) {
System.out.println(name + "注册到工厂中了....");
}
}
该回调方法的执行时机是在 Bean 依赖注入阶段之后,初始化之前
五、InitializingBean
InitializingBean 是一个可以在 Bean 的生命周期执行自定义操作的接口,凡是实现该接口的 Bean,在初始化阶段都可以执行自定义的操作。一般用在 @PostConstruct
失效时,用于替代他在初始化时执行一些代码。
在初始化阶段执行,@PostConstruct
之后、postProcessAfterInitialization
之前执行
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
从 InitializingBean 源码中可以看出它有一个 afterPropertiesSet 方法,当一个 Bean 实现该接口时,在 Bean 的初始化阶段,会回调 afterPropertiesSet 方法,其初始化阶段具体指 Bean 设置完属性之后。
该接口使用方式如下:
@Component
public class Test implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Test 执行初始化");
}
}
定义启动类:
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
结果:
...
2020-02-24 08:43:41.435 INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpTraceFilter' to: [/*]
2020-02-24 08:43:41.435 INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'webMvcMetricsFilter' to: [/*]
Test 执行初始化
2020-02-24 08:43:41.577 INFO 26193 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-02-24 08:43:41.756 INFO 26193 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@23529fee: startup date [Mon Feb 24 08:43:39 CST 2020]; root of context hierarchy
...
最终,afterPropertiesSet 方法被执行并打印输出语句。
六、循环依赖
1、场景
// A依赖了B
@Component
class A{
@Autowired
private B b;
}
// B依赖了A
@Component
class B{
@Autowired
private A a;
}
循环依赖就是A对象依赖了B对象,B对象依赖了A对象。如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。
但是,在 Spring 中循环依赖就是一个问题了,因为,在 Spring 中,一个对象并不是简单 new 出来了,而是会经过一系列的 Bean 的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。当然,在 Spring 中,出现循环依赖的场景很多,有的场景 Spring 自动帮我们解决了,而有的场景则需要程序员来解决。
几种循环依赖
第一种是自依赖,自己依赖自己从而形成循环依赖,一般情况下不会发生这种循环依赖,因为它很容易被我们发现。
第二种是直接依赖,发生在两个对象之间,比如:Bean A 依赖于 Bean B,然后 Bean B 又反过来依赖于 Bean A,如果比较细心的话肉眼也不难发现。
第三种是间接依赖,这种依赖类型发生在 3 个或者以上的对象依赖的场景,间接依赖最简单的场景:Bean A 依赖于 Bean B,Bean B 依赖于 Bean C,Bean C 依赖于 Bean A,可以想象当中间依赖的对象很多时,是很难发现这种循环依赖的,一般都是借助一些工具排查。
Spring对循环依赖的支持
这边只对单例 Bean 的注入进行讲解,其他的参考下面文章
https://www.cnblogs.com/mghio/p/15024461.html
2、Bean的生命周期
Bean的生成步骤如下:
- Spring 扫描 class 得到 BeanDefinition;
- 根据得到的 BeanDefinition 去生成 bean;
- 首先根据 class 推断构造方法;
- 根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象);
- 填充原始对象中的属性(依赖注入);
- 如果原始对象中的某个方法被 AOP 了,那么则需要根据原始对象生成一个代理对象;
- 把最终生成的代理对象放入单例池(源码中叫做 singletonObjects)中,下次 getBean 时就直接从单例池拿即
3、三级缓存
- 一级缓存为:singletonObjects;单例池,用于存放完全初始化好的 Bean,从该缓存中取出的 Bean 可以直接使用
- 二级缓存为:earlySingletonObjects;存放未初始化未填充属性提前暴露的Bean;用于存放提前暴露的单例对象的缓存,存放原始的 Bean 对象(属性尚未赋值),用于解决循环依赖
- 三级缓存为:singletonFactories;用于存放单例对象工厂的缓存,存放 Bean 工厂对象,用于解决循环依赖,缓存的是一个ObjectFactory,也就是一个Lambda表达式,在每个bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到, 如果当前bean没有出现循环依赖,那么这个Lambda表达式就没有用,当前bean按照自己的生命周期正常执行,执行完直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时出现了循环依赖,则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入到二级缓存(如果当前bean需要AOP,那么执行Lambda表达式,得到的就是对应的代理对象,如果无需AOP,则直接得到一个原始对象)
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name –> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name –> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name –> bean instance */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// ....
}
4、循环依赖解决方式

A 的 Bean 在创建过程中,在进行依赖注入之前,先把 A 的原始 Bean 放入缓存(提早暴露,只要放到缓存了,其他 Bean 需要时就可以从缓存中拿了),放入缓存后,再进行依赖注入,此时 A 的Bean 依赖了 B 的 Bean 。
如果 B 的 Bean 不存在,则需要创建 B 的 Bean,而创建 B 的 Bean 的过程和 A 一样,也是先创建一个 B 的原始对象,然后把 B 的原始对象提早暴露出来放入缓存中,然后在对 B 的原始对象进行依赖注入 A,此时能从缓存中拿到 A 的原始对象(虽然是 A 的原始对象,还不是最终的 Bean),B 的原始对象依赖注入完了之后,B 的生命周期结束,那么 A 的生命周期也能结束。
因为整个过程中,都只有一个 A 原始对象,所以对于 B 而言,就算在属性注入时,注入的是 A 原始对象,也没有关系,因为A 原始对象在后续的生命周期中在堆中没有发生变化。
5、singletonFactories作用
从上面这个分析过程中可以得出,只需要一个缓存就能解决循环依赖了,那么为什么 Spring 中还需要 singletonFactories 呢?
如果 A 的原始对象注入给 B 的属性之后,A 的原始对象进行了 AOP 产生了一个代理对象,此时就会出现,对于 A 而言,它的 Bean 对象其实应该是 AOP 之后的代理对象,而 B 的 a 属性对应的并不是 AOP 之后的代理对象,这就产生了冲突。
B 依赖的 A 和最终的 A 不是同一个对象。
那么如何解决这个问题?这个问题可以说二级缓存是没有办法解决。因为在一个 Bean 的生命周期最后,Spring提供了 BeanPostProcessor 可以去对 Bean 进行加工,这个加工不仅仅只是能修改 Bean 的属性值,也可以替换掉当前 Bean 。
在BeanPostProcessor 中可以完全替换掉某个 beanName 对应的 bean 对象。
而 BeanPostProcessor 的执行在 Bean 的生命周期中是处于属性注入之后的,循环依赖是发生在属性注入过程中的,所以很有可能导致,注入给 B 对象的 A 对象和经历过完整生命周期之后的 A 对象,不是一个对象。这就是有问题的。
所以在这种情况下的循环依赖,Spring 二级缓存是解决不了的,因为在属性注入时,Spring 也不知道 A 对象后续会经过哪些 BeanPostProcessor 以及会对 A 对象做什么处理。
6、AOP的循环依赖
虽然上面的情况可能发生,但是肯定发生得很少。某个 beanName 对应的最终对象和原始对象不是一个对象却会经常出现,这就是 AOP 。
AOP 就是通过一个 BeanPostProcessor 来实现的,在 Spring 中 AOP 利用的要么是 JDK 动态代理,要么 CGLib 的动态代理,所以如果给一个类中的某个方法设置了切面,那么这个类最终就需要生成一个代理对象。
一般过程就是:A 类—>生成一个普通对象–>属性注入–>基于切面生成一个代理对象–>把代理对象
放入 singletonObjects 单例池中。

而 AOP 可以说是 Spring 中除开 IOC 的另外一大功能,而循环依赖又是属于 IOC 范畴的,所以这两大功能想要并存,Spring 需要特殊处理。
如何处理的,就是利用了第三级缓存 singletonFactories。
首先,singletonFactories 中存的是某个 beanName 对应的 ObjectFactory,在 bean 的生命周期中,生成完原始对象之后,就会构造一个 ObjectFactory 存入 singletonFactories 中。

https://blog.csdn.net/weixin_44129618/article/details/122839774
7、singletonFactories 源码
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
其实 ObjectFactory
就是一个 Lambda 表达式,用来获取经过 BeanPostProcessor
后处理器后的 Bean
protected Object doCreateBean(String beanName,
RootBeanDefinition mbd,
@Nullable Object[] args)
throws BeanCreationException {
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
}
这里获取到 bean 对应所有的 后处理器,循环执行代理,覆盖原本的Bean
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}