夯實Spring系列|第十四章:Spring Bean 生命週期-下篇

夯實Spring系列|第十四章:Spring Bean 生命週期-下篇

本章說明

本文是 Spring Bean 生命週期系列的最後一篇,會對 Spring Bean 初始化階段以及後面的銷燬階段進行分析和討論。Aware 回調源碼其實是在 initializeBean 方法中 (初始化 Bean 階段),所以也可以當成是 Spring Bean 初始化階段。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pdvWTz6R-1588321832427)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200429125110856.png)]

1.項目環境

2.Spring Bean Aware 接口回調階段

Spring Aware 接口(此接口順序也是源碼的回調執行順序)

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • EnvironmentAware
  • EmbeddedValueResovlerAware
  • ResourceLoaderAware
  • ApplicationEventPublisherAware
  • MessageSourceAware
  • ApplicationContextAware

2.1 示例改造1

UserHolder 分別實現 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware 三個回調接口

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {

    private User user;

    private Integer number;

    private String description;

    public UserHolder(User user) {
        this.user = user;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }


    @Override
    public String toString() {
        return "UserHolder{" +
                "user=" + user +
                ", number=" + number +
                ", description='" + description + '\'' +
                ", beanName='" + beanName + '\'' +
                '}';
    }

    private ClassLoader classLoader;

    private BeanFactory beanFactory;

    private String beanName;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

使用之前的 BeanInstantiationLifecycleDemo 示例代碼,執行結果

UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder'}

2.2 源碼分析1

AbstractAutowireCapableBeanFactory#doCreateBean 595 行,同樣還是 doCreateBean 方法,但是之前是屬性賦值階段 populateBean,現在是 initializeBean 階段。
在這裏插入圖片描述
繼續往下
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HfDrzgw6-1588321832432)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200430091207719.png)]
源碼位置 AbstractAutowireCapableBeanFactory#invokeAwareMethods,通過源碼我們可以看到分別對 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 進行判斷。

	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

2.3 ApplicationContext 生命週期 Aware 回調

繼續改造上面的示例

UserHolder,我們再實現一個 EnvironmentAware 回調

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware {

    private User user;

    private Integer number;

    private String description;

    public UserHolder(User user) {
        this.user = user;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "UserHolder{" +
                "user=" + user +
                ", number=" + number +
                ", description='" + description + '\'' +
                ", beanName='" + beanName + '\'' +
                ", environment=" + environment +
                '}';
    }

    private ClassLoader classLoader;

    private BeanFactory beanFactory;

    private String beanName;

    private Environment environment;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}

執行結果:

UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=null}

可以看到 environment=null,setEnvironment() 打上斷點,也不會執行,說明 EnvironmentAware 沒有被回調。

其實原因是這些 Aware 回調接口是 ApplicationContext 生命週期中的,並不在 BeanFactory 生命週期中,這是 BeanFactory 和 ApplicationContext 的一個具體區別之一。

2.4 示例改造2

所以我們這裏需要再對示例代碼進行改造觸發 ApplicationContext 生命週期中

/**
 * Bean 實例化生命週期
 */
public class BeanInstantiationLifecycleDemo {
    public static void main(String[] args) {
        executeBeanFactory();
        System.out.println("------------------");
        executeApplicationContext();
    }

    private static void executeApplicationContext(){
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(locations);

        //第一種添加 BeanpostBeanProcess 實現方式:
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
//        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //第二種添加 BeanpostBeanProcess 實現方式:
        //將 <bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/> 配置在 xml 中

        applicationContext.refresh();

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);

        System.out.println(userHolder);

        applicationContext.close();
    }


    private static void executeBeanFactory(){
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //內部類 無法添加 ApplicationContextAwareProcessor
//        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(beanFactory));

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);
//        System.out.println("Bean 定義的數量: " + count);
//        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
//        Stream.of(beanDefinitionNames).forEach(System.out::println);

        User user = beanFactory.getBean("user", User.class);
        SuperUser superUser = beanFactory.getBean("superUser", SuperUser.class);
        // 構造器注入是按照類型注入,resolveDependency
        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);

        System.out.println(userHolder);
    }

}

將 MyInstantiationAwareBeanPostProcess 獨立成一個單獨的類,不在作爲內部類

bean-constructor-injection.xml 加入 MyInstantiationAwareBeanPostProcess 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

    <bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/>

    <bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
          autowire="constructor">
        <!--<property name="number" value="1"/>-->
        <property name="description" value="The user holder" />
    </bean>

</beans>

執行結果:

UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=null}
------------------
UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[PropertiesPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]}}

可以看到 BeanFactory 的方式無法回調 EnvironmentAware,而 ApplicationContext 可以。

2.5 源碼分析2

我們看一下 AbstractApplicationContext#prepareBeanFactory 中如何進行 Aware 回調

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        ...
		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

關鍵代碼 ApplicationContextAwareProcessor 我們再看下 ApplicationContextAwareProcessor 具體實現

ApplicationContextAwareProcessor#invokeAwareInterfaces

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

代碼和 BeanNameAware 的回調如出一轍。

3.Spring Bean 初始化前階段

初始化前階段已完成以下三個階段

  • Bean 實例化
  • Bean 屬性賦值
  • Bean Aware 接口回調

方法回調

  • BeanPostProcessor#postProcessBeforeInitialization

3.1 示例代碼

爲了打印方便我們可以把 UserHolder#toString 方法改造一下

    @Override
    public String toString() {
        return "UserHolder{" +
                "number=" + number +
                ", description='" + description +
                ", user=" + user +
                '}';
    }

MyInstantiationAwareBeanPostProcess 新增 postProcessBeforeInitialization 的實現

public class MyInstantiationAwareBeanPostProcess implements InstantiationAwareBeanPostProcessor {
    /**
     * 實例化前階段
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "superUser") && SuperUser.class.equals(beanClass)) {
            SuperUser user = new SuperUser();
            user.setName("new-superUser v1");
            return user;
        }
        return null;
    }

    /**
     * 實例化後階段
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "user") && User.class.equals(bean.getClass())) {
            //"user" 對象不允許屬性賦值(配置元信息-> 屬性值)
            User user = User.class.cast(bean);
            user.setId(2L);
            user.setName("after-superUser v2");
            return false;//返回 false 表示忽略掉配置元信息,比如 <bean ...<property name = id value = 1/>
        }
        return true;
    }


    // user 跳過 Bean 屬性賦值
    // superUser 也是完全跳過 Bean 實例化
    // 這裏我們只能攔截 UserHolder
    /**
     * 屬性賦值前階段
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
            final MutablePropertyValues propertyValues;
            // 兼容 pvs 爲空的情況 pvs 對應xml中配置的 <property .../>
            if (pvs instanceof MutablePropertyValues) {
                propertyValues = (MutablePropertyValues) pvs;
            } else {
                propertyValues = new MutablePropertyValues();
            }
            // 此操作等價於 <property name="number" value="1"/>
            propertyValues.addPropertyValue("number", "1");
            if (propertyValues.contains("description")) {
                // PropertyValue 無法直接覆蓋,因爲是 final 類型
                PropertyValue description = propertyValues.getPropertyValue("description");
                propertyValues.removePropertyValue("description");
                propertyValues.addPropertyValue("description", "The user holder v2");
                System.out.println("屬性賦值前階段 : postProcessProperties() -> The user holder v2");

            }
            return propertyValues;
        }
        return null;
    }

    /**
     * 初始化前階段
     * 這個接口實際上是覆蓋的 BeanPostProcessor 中的方法
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
            UserHolder user = UserHolder.class.cast(bean);
            user.setDescription("The user holder v3");
            System.out.println("初始化前階段 : postProcessBeforeInitialization() -> The user holder v3");
        }
        return bean;
    }

}

調用示例 BeanInitializationLifecycleDemo

/**
 * Bean 初始化生命週期
 */
public class BeanInitializationLifecycleDemo {
    public static void main(String[] args) {
        executeBeanFactory();
    }

    private static void executeBeanFactory() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);

        System.out.println(userHolder);
    }

}

執行結果:

屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
UserHolder{number=1, description='The user holder v3, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

3.2 源碼分析

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
        // 同樣也是遍歷我們所有的 BeanPostProcessor 
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 執行 postProcessBeforeInitialization 獲取返回結果 如果爲 null 就返回當前 bean
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

4.Spring Bean 初始化階段

Bean 初始化(Initialization)

  • @PostConstruct 標註方法
  • 實現 InitializingBean 接口的 afterPropertiesSet() 方法
  • 自定義初始化方法

4.1 示例改造

UserHolder 我們分別加入三種初始化的方式,需要注意的是 @PostConstruct 是 Java 通用註解,需要特殊的方式進行觸發,相關文章 第九章:IoC 依賴注入(專題)-下 10.Java 通用注入原理 小節

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean {

    private User user;

    private Integer number;

    private String description;

    public UserHolder(User user) {
        this.user = user;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @PostConstruct
    public void init(){
        this.description = "The userHolder v4";
        System.out.println("初始化階段 : @PostConstruct -> The user holder v4");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        this.description = "The userHolder v5";
        System.out.println("初始化階段 : afterPropertiesSet() -> The user holder v5");
    }

    public void customInit() throws Exception {
        this.description = "The userHolder v6";
        System.out.println("初始化階段 : customInit() -> The user holder v6");
    }

    @Override
    public String toString() {
        return "UserHolder{" +
                "number=" + number +
                ", description='" + description +
                ", user=" + user +
                '}';
    }

    private ClassLoader classLoader;

    private BeanFactory beanFactory;

    private String beanName;

    private Environment environment;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

}

bean-constructor-injection.xml 文件 bean 增加 init-method=“customInit” 屬性

    <bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
          autowire="constructor" init-method="customInit">
        <!--<property name="number" value="1"/>-->
        <property name="description" value="The user holder" />
    </bean>

調用示例 BeanInitializationLifecycleDemo

/**
 * Bean 初始化生命週期
 */
public class BeanInitializationLifecycleDemo {
    public static void main(String[] args) {
        executeBeanFactory();
    }

    private static void executeBeanFactory() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);

        System.out.println(userHolder);
    }

}

執行結果:

屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
UserHolder{number=1, description='The userHolder v6, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

4.2 源碼分析

從源碼可以很清晰的看到 初始化前 -> 初始化 -> 初始化後 三個階段
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Kmvd9QAI-1588321832434)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200430161813049.png)]
過程相對簡單,這裏就不一 一截圖演示了,可對照源碼位置打上斷點進行調試:

  • afterPropertiesSet

AbstractAutowireCapableBeanFactory#invokeInitMethods 1855 行

((InitializingBean) bean).afterPropertiesSet();

  • 自定義方法

AbstractAutowireCapableBeanFactory#invokeInitMethods 1864 行

invokeCustomInitMethod(beanName, bean, mbd);

  • @PostContruct

其實在初始化前的操作中就已經完成了 postProcessBeforeInitialization

InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethods 333 行

5.Spring Bean 初始化後階段

方法回調

  • BeanPostProcessor#postProcessAfterInitialization

5.1 示例改造

和初始化前的階段一樣,我們只需要重寫 BeanPostProcessor 中的 postProcessAfterInitialization 方法即可

public class MyInstantiationAwareBeanPostProcess implements InstantiationAwareBeanPostProcessor {
    ... //省略掉之前的階段代碼

    /**
     * 初始化後階段
     * 這個接口實際上是覆蓋的 BeanPostProcessor 中的方法
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
            UserHolder user = UserHolder.class.cast(bean);
            user.setDescription("The user holder v7");
            System.out.println("初始化後階段 : postProcessAfterInitialization() -> The user holder v7");
        }
        return bean;
    }

}

執行結果:

屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
UserHolder{number=1, description='The user holder v7, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

5.2 源碼分析

這個源代碼和初始化前階段的 applyBeanPostProcessorsBeforeInitialization 源碼基本上完全一樣

  • 遍歷所有的 BeanPostProcessor 執行 postProcessAfterInitialization 方法
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

5.3 小結

從上面源碼分析可以看出 initializeBean 初始化 Bean 的方法依次進行了四個操作

  • invokeAwareMethods(beanName, bean); //Aware回調
  • applyBeanPostProcessorsBeforeInitialization //初始化前
  • invokeInitMethods //初始化
  • applyBeanPostProcessorsAfterInitialization //初始化後

6.Spring Bean 初始化完成階段

方法回調

  • Spring 4.1+: SmartInitializingSingleton#afterSingletonsInstantiated

6.1 示例改造

UserHolder 實現 SmartInitializingSingleton 接口

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean,SmartInitializingSingleton {

    private User user;

    private Integer number;

    private String description;

    public UserHolder(User user) {
        this.user = user;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @PostConstruct
    public void init(){
        this.description = "The userHolder v4";
        System.out.println("初始化階段 : @PostConstruct -> The user holder v4");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        this.description = "The userHolder v5";
        System.out.println("初始化階段 : afterPropertiesSet() -> The user holder v5");
    }

    public void customInit() throws Exception {
        this.description = "The userHolder v6";
        System.out.println("初始化階段 : customInit() -> The user holder v6");
    }

    @Override
    public String toString() {
        return "UserHolder{" +
                "number=" + number +
                ", description='" + description +
                ", user=" + user +
                '}';
    }

    private ClassLoader classLoader;

    private BeanFactory beanFactory;

    private String beanName;

    private Environment environment;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void afterSingletonsInstantiated() {
        this.description = "The userHolder v8";
        System.out.println("初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8");
    }
}

afterSingletonsInstantiated 這個方法此時還不能被回調,我們需要通過 Idea 來查找這個方法在哪裏被調用過,

DefaultListableBeanFactory#preInstantiateSingletons,所以我們需要在代碼中顯示的調用這個方法

beanFactory.preInstantiateSingletons();

/**
 * Bean 初始化生命週期
 */
public class BeanInitializationLifecycleDemo {
    public static void main(String[] args) {
        executeBeanFactory();
    }

    private static void executeBeanFactory() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);
        // 通常在 ApplicationContext 場景使用
        beanFactory.preInstantiateSingletons();

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);

        System.out.println(userHolder);
    }

}

執行結果:

user用戶對象初始化...
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
UserHolder{number=1, description='The userHolder v8, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

6.2 備註

SmartInitializingSingleton 通常在 ApplicationContext 場景使用,因爲在應用上下文啓動過程中,AbstractApplicationContext#refresh 中 finishBeanFactoryInitialization(beanFactory); 會顯示的調用這個 preInstantiateSingletons() 方法。

preInstantiateSingletons 在 AbstractApplicationContext 場景非常重要,有兩層含義

  • 初始化我們所有的 Spring Bean
    • 通過 beanDefinitionNames 來遍歷我們所有的 BeanDefintion,逐一進行 getBean(beanName) 操作,通過我們的 BeanDefinition 創建 bean 對象,並緩存到 DefaultSingletonBeanRegistry#singletonObjects 中
  • 當我們的 Spring Bean 全部初始化完成之後,再進行 afterSingletonsInstantiated() 方法的回調

7.Spring Bean 銷燬前階段

方法回調

  • DestructionAwareBeanPostProcessor#postProcessBeforeDestruction

7.1 示例代碼

新增 MyDestructionAwareBeanPostProcessor 實現 DestructionAwareBeanPostProcessor

覆蓋 postProcessBeforeDestruction 銷燬前的方法

public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
            UserHolder user = UserHolder.class.cast(bean);
            user.setDescription("The user holder v9");
            System.out.println("銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9");
        }
    }
    
}

調用需要的執行 beanFactory.destroyBean("userHolder",userHolder); 銷燬這個 bean 纔會觸發銷燬前的過程。

/**
 * Bean 完整生命週期
 */
public class BeanLifecycleDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
        // 添加 DestructionAwareBeanPostProcessor 銷燬前
        beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);

        beanFactory.preInstantiateSingletons();

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
        beanFactory.destroyBean("userHolder",userHolder);
        System.out.println(userHolder);
    }

}

執行結果:

屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
UserHolder{number=1, description='The user holder v9, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

7.2 源碼調試

org.springframework.beans.factory.support.DisposableBeanAdapter#destroy

循環遍歷 beanPostProcessors,執行 postProcessBeforeDestruction 方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-p9Uf69ls-1588321832436)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200501135005300.png)]

8.Spring Bean 銷燬階段

Bean 銷燬(Destroy)

  • @PreDestroy 標註方法
  • 實現 DisposableBean 接口的 destroy() 方法
  • 自定義銷燬方法

8.1 示例方法

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean,SmartInitializingSingleton, DisposableBean {
    ...//省略掉其他重複代碼

    @PreDestroy
    public void preDestroy(){
        this.description = "The userHolder v10";
        System.out.println("銷燬階段 : @PreDestroy -> The user holder v10");
    }

    @Override
    public void destroy() throws Exception {
        this.description = "The userHolder v11";
        System.out.println("初始化階段 : DisposableBean#destroy -> The user holder v11");
    }

    public void customDestroy(){
        this.description = "The userHolder v12";
        System.out.println("初始化階段 : customDestroy -> The user holder v12");
    }

}

bean-constructor-injection.xml 增加 destroy-method="customDestroy" 屬性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>

    <bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/>

    <bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
          autowire="constructor" init-method="customInit" destroy-method="customDestroy">
        <!--<property name="number" value="1"/>-->
        <property name="description" value="The user holder" />
    </bean>

</beans>

調用示例,注意 DestructionAwareBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 的添加順序,因爲 @PostConstruct、@PreDestroy 由 CommonAnnotationBeanPostProcessor 觸發,但是 BeanPostProcessor 的添加是 FIFO 的模式,所以 DestructionAwareBeanPostProcessor 必須在之前進行添加。

/**
 * Bean 完整生命週期
 */
public class BeanLifecycleDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //添加 DestructionAwareBeanPostProcessor 銷燬前
        beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
        //添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);

        beanFactory.preInstantiateSingletons();

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
        beanFactory.destroyBean("userHolder",userHolder);
        System.out.println(userHolder);
    }

}

執行結果:

屬性賦值前階段 : postProcessProperties() -> The user holder v2
Disconnected from the target VM, address: '127.0.0.1:51595', transport: 'socket'
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
銷燬階段 : @PreDestroy -> The user holder v10
初始化階段 : DisposableBean#destroy -> The user holder v11
初始化階段 : customDestroy -> The user holder v12
UserHolder{number=1, description='The userHolder v12, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}

8.2 源碼調試

DisposableBeanAdapter#destroy 242 行,可以看到有兩個 beanPostProcessor,分別是我們添加的 DestructionAwareBeanPostProcessor、CommonAnnotationBeanPostProcessor

1.DestructionAwareBeanPostProcessor 執行銷燬前的方法

2.CommonAnnotationBeanPostProcessor 觸發 @PreDestroy 銷燬方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PwpbVJ3z-1588321832437)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200501144444266.png)]
258 行,執行 DisposableBean#destroy 方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KljkXnZT-1588321832438)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200501144748023.png)]
273 行,執行我們自定義的方法 customDestroy
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UCdEtMbn-1588321832438)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200501144907529.png)]

9.Spring Bean 垃圾收集

Bean 垃圾回收

  • 關閉 Spring 容器(應用上下文)
  • 執行 GC
  • Spring Bean 覆蓋 finalize() 方法被回調

9.1 示例改造

UserHolder 覆蓋 Object#finalize 方法,因爲這個方法會在對象被 GC 的時候調用

public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean, SmartInitializingSingleton, DisposableBean {
    ...//省略重複代碼
    @Override
    public void finalize() throws Throwable {
        System.out.println(beanName + " 被垃圾回收");
    }
}

調用示例中添加

  • beanFactory.destroySingletons();//銷燬掉所有單例對象,保證沒有對象的強引用,導致無法 gc
  • userHolder=null;//對象置爲空
  • System.gc(); //調用 Full gc
/**
 * Bean 完整生命週期
 */
public class BeanLifecycleDemo {
    public static void main(String[] args) throws InterruptedException {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //添加 BeanpostBeanProcess 實現
        beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
        //添加 DestructionAwareBeanPostProcessor 銷燬前
        beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
        //添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
        int count = reader.loadBeanDefinitions(locations);

        beanFactory.preInstantiateSingletons();

        UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
//        beanFactory.destroyBean("userHolder",userHolder);
        beanFactory.destroySingletons();
        System.out.println(userHolder);
        userHolder=null;
        System.gc();
        Thread.sleep(5000);
    }

}

執行結果:

user用戶對象初始化...
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
銷燬階段 : @PreDestroy -> The user holder v10
初始化階段 : DisposableBean#destroy -> The user holder v11
初始化階段 : customDestroy -> The user holder v12
user用戶對象銷燬...
UserHolder{number=1, description='The userHolder v12, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
userHolder 被垃圾回收

10.面試題

10.1 BeanPostProcessor 的使用場景有哪些?

BeanPostProcessor 提供 Spring Bean 初始化前和初始化後的生命週期回調,分別對應 postProcessBeforelnitialization 以及 pistProcessAfterInitialization 方法,允許對相關的 Bean 進行擴展,甚至是替換。

BeanPostProcessor 的子類 DestructionAwareBeanPostProcessor 提供銷燬前的生命週期回調。
BeanPostProcessor 的子類 InstantiationAwareBeanPostProcessor 提供實例化前postProcessBeforeInstantiation,實例化後 postProcessAfterInstantiation,屬性賦值前 postProcessProperties 的生命週期回調。

加分項:其中 ApplicationContext 相關的 Aware 回調也是基於 BeanPostProcessor 實現,即 ApplicationContextAwareProcessor。

10.2 BeanFactoryPostProcessor 與 BeanPostProcessor 的區別?

其實兩者無法進行對比,BeanFactoryPostProcessor 是 Spring BeanFactory(實際是ConfigurableListableBeanFactory)的後置處理器,用於擴展 BeanFactory,或者通過 BeanFactory 進行依賴查找和依賴注入。
而 BeanPostProcessor 則是直接與 BeanFactory 關聯,屬於 N 對 1 的關係。

加分項:BeanFactoryPostProcessor 必須有 Spring ApplicationContext 執行,BeanFactory 無法直接與其交互。

10.3 BeanFactory 是怎樣處理 Bean 生命週期?

BeanFactory 的默認實現爲 DefaultListableBeanFactory ,其中 Bean 生命週期與方法映射如下:

  • BeanDefinition 註冊階段 - registerBeanDefinition

  • BeanDefinition 合併階段 - getMergedBeanDefinition

  • Bean 實例化前階段 - resolveBeforeInstantiation

  • Bean 實例化階段 - createBeanInstance

  • Bean 實例化後階段 - populateBean

  • Bean 屬性賦值前階段 - populateBean

  • Bean 屬性賦值階段 - populateBean

  • Bean Aware 接口回調階段 - initializeBean

  • Bean 初始化前階段 - initializeBean

  • Bean 初始化階段 - initializeBean

  • Bean 初始化後階段 - initializeBean

  • Bean 初始化完成階段 - preInstantiateSingletons

  • Bean 銷燬前階段 - destroyBean

  • Bean 銷燬階段 - destroyBean

11.參考

  • 極客時間-小馬哥《小馬哥講Spring核心編程思想》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章