Spring源码(7)-Bean的生命周期


一、Bean生命周期

Spring中的一个Bean从生到灭要经历很多过程,总体分为Bean定义、实例化、属性赋值(依赖注入)、初始化、生存期、销毁几个阶段:

在这里插入图片描述

BeanPostProcessor 接口可以对Bean生命周期中的很多部分进行扩展,并且Spring容器中有很多内建的 BeanPostProcessor 对Spring Bean的功能进行支持。BeanPostProcessor 不仅在IOC上发挥了重要作用,在AOP上也发挥了重要的作用。搞懂了Spring内置的BeanPostProcessor的功能,基本上就把Spring Bean的生命周期搞懂了。

Spring Bean的生命周期上面图二已经展示,可以主要分为如下4个部分:

(1)处理BeanDefinitionBeanDefinition解析,注册,合并

(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个方法 postProcessBeforeInitializationpostProcessAfterInitialization都是在目标对象被实例化之后,并且属性也被设置之后调用的

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 是用于管理注入元数据的内部类。不打算直接用于应用程序。

AutowiredAnnotationBeanPostProcessororg.springframework.context.annotationcommonannotationbeanpostprocessororg.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor 使用。

image-20220521200129329

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

BeanFactoryPostProcessorBeanPostProcessor 类似,可以对 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后处理器的注解失效

此时该配置类的生命周期如下

  • 配置类的创建和初始化,执行AwareInitializingBean
  • 执行工厂后处理器
  • 注册 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对循环依赖的支持

image-20230302211606829

这边只对单例 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、循环依赖解决方式

image-20230302212125341

image-20230302212249849

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 单例池中

image-20230302212732605

而 AOP 可以说是 Spring 中除开 IOC 的另外一大功能,而循环依赖又是属于 IOC 范畴的,所以这两大功能想要并存,Spring 需要特殊处理。

如何处理的,就是利用了第三级缓存 singletonFactories。

首先,singletonFactories 中存的是某个 beanName 对应的 ObjectFactory,在 bean 的生命周期中,生成完原始对象之后,就会构造一个 ObjectFactory 存入 singletonFactories 中。

image-20230302212817402

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);
        }
    }
}

  目录