Spring 4.x 源码系列5-bean的生命周期

一、前沿

学习了 bean创建bean加载 之后我们了解了 Spring IOC 容器对于托管对象bean的管理,bean的生命周期也完全有 Spring IOC 容器管理。Spring的ioc容器功能非常强大,负责Spring的Bean的创建和管理等功能。而Spring 的 bean 是整个Spring应用中很重要的一部分,了解Spring Bean的生命周期对我们了解整个spring框架会有很大的帮助

BeanFactory ApplicationContext 是 Spring 中两种非常重要的容器,功能分别如下:

BeanFactory:提供了创建bean和依赖注入的支持

ApplicationContext: 除了拥有 BeanFactory 的功能外,还增加了一些扩展功能,例如增加了事件传播资源访问国际化的消息访问等功能

bean 完成的生命周期如下图所示:

下面分别介绍 ApplicationContext 和 BeanFactory 两种容器的 bean 的生命周期

二、ApplicationContext Bean 生命周期

首先看 ApplicationContext Bean 的生命周期图,如下所示:

ApplicationContext 容器,Bean 的生命周期流程大致如下:

2.1 实例化bean(创建bean实例 BeanWrapper)

对于 ApplicationContext 容器,当容器启动后,便会实例化所有的 bean,容器通过获取 BeanDefinition(bean定义) 对象中信息进行实例化。注意这一步仅仅是简单的实例化而已,并没有初始化和依赖注入,创建好的 bean 实例被包装成 BeanWrapper 对象,BeanWrapper 提供了设置对象属性的接口,从而避免了使用反射机制设置bean属性

2.2 填充属性(初始化bean属性)

实例化后的对象 BeanWrapper 此时是一个原生的状态,并没有进行任何属性的设置,包括依赖注入。 紧接着 Spring 会根据 BeanDefinition 中的信息进行依赖注入。
并通过 BeanWrapper 提供的设置属性的接口完成依赖注入

2.3 注入 xxxAware接口

Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给bean,如下所示:

1)、如果 Bean 实现了 BeanNameAware 接口,则会调用该接口的 setBeanName 方法,传入该 Bean 的 id,这样该 Bean 就获得了自己在配置文件中的 id

2)、如果 Bean 实现了 BeanFactoryAware 接口,则会该接口的 setBeanFactory 方法,传入该 Bean 的 BeanFactory,这样该 Bean 就获得了自己所在的 BeanFactory 对象

3)、如果 Bean 实现了 ApplicationContextAware 接口,则会调用该接口的 setApplicationContext 方法,传入该 Bean 的 ApplicationContext,这样该 Bean 就获得了自己所在的 ApplicationContext 对象

2.4 BeanPostProcessor 接口

经过上述3个步骤之后,bean 对象已经被构造好了,如果你想要在对象使用前做一些自定义的处理的话,就可以通过实现 BeanPostProcessor 接口完成处理,该接口提供了两个重要的方法:

postProcessBeforeInitialization( Object bean, String beanName ) : 传入当前正在被初始化的 bean 和 beanName,此时可以对 bean 做自定义的处理,由于此方法会先于 InitialzationBean 接口方法执行,故此称为前置处理

postProcessAfterInitialization( Object bean, String beanName ) : 传入当前正在被初始化的 bean 和 beanName,此时可以对 bean 做自定义的处理,由于此方法会在 InitialzationBean 接口方法调用完成之后执行,故此称为后置处理

2.5 InitialzationBean 接口和 init-method 方法

当 BeanPostProcessor 的前置处理之后,如果 bean 实现了 InitialzationBean 接口,则会调用 InitializingBean 接口的 afterPropertiesSet 方法

InitializingBean 接口只有一个方法,即 afterPropertiesSet(),它没有任何传参,因此不能对 bean 做任何的处理,但是可以实现一些额外的业务逻辑

Spring 为了降低对客户代码的侵入性,还给 bean 的配置提供了 init-method 属性,通过该属性用户可以配置想要执行的方法

经过此步骤之后,就可以正式使用该Bean了,对于 scope 为 singleton 类型的 Bean,Spring IOC 容器中会缓存该 bean 的实例,而对于 scope 为 prototype 类型的 Bean,每次被调用都会new一个新的对象,其生命周期就交给调用方管理了,不再由 Spring 容器对其进行管理了

2.6 DisposableBean 接口和 destroy-meythod 方法

容器关闭后,如果 Bean 实现了 DisposableBean 接口,则会调用该接口的 destroy 方法销毁bean

同样的,Spring 为了降低对客户代码的侵入性,还给 bean 的配置提供了 destroy-method 属性,通过该属性用户可以配置销毁bean后想要执行的方法

至此,整个 Bean 的生命周期结束

demo示例

1)、自定义 BeanPostProcessor,代码如下:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * 自定义BeanPostProcessor
 *
 * @date 2019-12-24 11:23
 **/
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean,
                                                  String beanName) throws BeansException {
        System.out.println("BeanPostProcessor postProcessBeforeInitialization 方法被调用");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean,
                                                 String beanName) throws BeansException {
        System.out.println("BeanPostProcessor postProcessAfterInitialization 方法被调用");
        return bean;
    }
}

2)、TestBean 实体类,代码如下:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 测试bean
 *
 * @date 2019-12-24 11:17
 **/
public class TestBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    public TestBean() {
        System.out.println("TestBean 构造方法被调用");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware 的 setBeanFactory 方法被调用");
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware 的 setBeanName 方法被调用");
        this.beanName = name;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware 的 setApplicationContext 方法被调用");
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean 的 afterPropertiesSet 方法被调用");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean 的 destroy 方法被调用");
    }

    public void myInitMethod(){
        System.out.println("自定义的 myInitMethod 方法被调用");
    }

    public void myDestroyMethod(){
        System.out.println("自定义的 myDestroyMethod 方法被调用");
    }
}

3)、测试类代码如下:

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * ApplicationContext测试
 *
 * @date 2019-12-24 11:31
 **/
public class ApplicationContextTest {
    public static void main(String[] args) {
        System.out.println("开始初始化ApplicationContext容器");
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application_context.xml");
        System.out.println("ApplicationContext容器初始化完毕");
        applicationContext.close();
    }
}

4)、src/test/resources/application_context.xml 配置文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>

	<!-- 自定义BeanPostProcessor -->
	<bean id="myBeanPostProcessor" class="com.springboot.demo.bean.MyBeanPostProcessor"/>

	<!-- 测试bean -->
	<bean id="testBean" class="com.springboot.demo.bean.TestBean" init-method="myInitMethod" 
		  destroy-method="myDestroyMethod"/>
</beans>

5)、运行结果如下:

开始初始化ApplicationContext容器
TestBean 构造方法被调用
BeanNameAware 的 setBeanName 方法被调用
BeanFactoryAware 的 setBeanFactory 方法被调用
ApplicationContextAware 的 setApplicationContext 方法被调用
BeanPostProcessor postProcessBeforeInitialization 方法被调用
InitializingBean 的 afterPropertiesSet 方法被调用
自定义的 myInitMethod 方法被调用
BeanPostProcessor postProcessAfterInitialization 方法被调用
ApplicationContext容器初始化完毕
DisposableBean 的 destroy 方法被调用
自定义的 myDestroyMethod 方法被调用

运行结果可以看出,和 ApplicationContext Bean 的生命周期图上的流程一致

三、BeanFactory Bean 生命周期

BeanFactory Bean 的生命周期图,如下所示:

从上图中可知,BeanFactory Bean 的生命周期和 ApplicationContext Bean 的生命周期步骤上基本上一致,对于相同点这里不在做重复说明了,下面只分析其不同点:

1)、BeanFactory 容器不会调用 ApplicationContextAware 接口的 setApplicationContext 方法

2)、BeanPostProcessor 接口的 postProcessBeforeInitialzation 方法和 postProcessAfterInitialization 方法不会自动调用,即使 xml 中配置了 BeanPostProcessor 也没有用,必须自己通过代码手动注册

3)、BeanFactory 容器启动的时候,不会去实例化所有的 Bean,包括所有scope为singleton且非懒加载的 Bean 也是一样,而是在调用的时候(getBean 方法调用)才去实例化

demo示例

自定义 BeanPostProcessor 、TestBean 和 配置文件内容全部不变,只有测试类修改了,如下所示:

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

import com.springboot.demo.bean.MyBeanPostProcessor;

/**
 * BeanFactory测试
 *
 * @date 2019-12-24 14:17
 **/
public class BeanFactoryTest {
    public static void main(String[] args) {
        System.out.println("开始初始化BeanFactory容器");
        ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application_context.xml"));
        System.out.println("BeanFactory容器初始化完毕");
        // 这里必须手动注册 BeanPostProcessor
        beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
        // 必须调用 BeanFactory 的 getBean 方法,不然 bean 是不会实例化的,因为 BeanFactory 中的 bean 都是懒加载
        beanFactory.getBean("testBean");
        beanFactory.destroySingletons();
    }
}

运行结果如下:

开始初始化BeanFactory容器
BeanFactory容器初始化完毕
TestBean 构造方法被调用
BeanNameAware 的 setBeanName 方法被调用
BeanFactoryAware 的 setBeanFactory 方法被调用
BeanPostProcessor postProcessBeforeInitialization 方法被调用
InitializingBean 的 afterPropertiesSet 方法被调用
自定义的 myInitMethod 方法被调用
BeanPostProcessor postProcessAfterInitialization 方法被调用
DisposableBean 的 destroy 方法被调用
自定义的 myDestroyMethod 方法被调用

运行结果可以看出,和 BeanFactory Bean 的生命周期图上的流程一致

四、总结

对于 Bean 的生命周期管理有 ApplicationContext 和 BeanFactory,Spring 建议大家使用 ApplicationContext 方式获取 bean,而 BeanFactory 方式目前已经被 Spring 舍弃,不建议大家使用 BeanFactory 方式获取 bean

参考:

https://www.jianshu.com/p/3944792a5fff

https://www.zhihu.com/question/38597960

猜你喜欢

转载自blog.csdn.net/ywlmsm1224811/article/details/103669833