天天看點

Spring Bean生命周期詳解和應用(上)

作者:老男孩的成長之路

前言

基本的思路是:

  1. 整體有個概念的了解
  2. 對總體生命周期有個初步的感覺
  3. 重新梳理下生命周期 結合源碼進一步了解 主要看看擴充點
  4. 實際應用的舉例

希望此次能更加通俗易懂、友善記憶。

了解整體

Spring容器隻管理singleton作用域下的Bean,Spring能夠精确地知道該Bean何時被建立,何時初始化完成,以及何時被銷毀。

而對于prototype的bean,spring 隻負責建立,當容器建立了Bean的執行個體之後不會跟蹤其生命周期,直接交給用戶端代碼管理。

了解spring bean的生命周期可以在不同的階段進行介入完成一些需要的操作,比如在bean已經注入依賴的屬性bean之後我們需要對屬性bean進行自定義配置可以使用@PostContruct,比如在client類bean要銷毀之前需要釋放連接配接可以使用@PreDestroy。

相比普通的java對象,我們需要自己去劃分這些生命周期階段,語言并沒有提供,隻有一個Object#finalize可以在垃圾回收之前執行一些清理。

總體感覺生命周期

package com.study.bean.lifecycle;

import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
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 javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Slf4j
@ToString
public class Person implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean{
    private String name;
    private String address;
    private Integer phone;
    private BeanFactory beanFactory;
    private String beanName;

    public Person() {
        log.info("【構造器】調用Person的構造器執行個體化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        log.info("[注入屬性]name:{}",name);
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        log.info("[注入屬性]address:{}",address);
        this.address = address;
    }

    public Integer getPhone() {
        return phone;
    }

    public void setPhone(Integer phone) {
        log.info("【注入屬性】phone:{}",phone);
        this.phone = phone;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        log.info("【BeanFactoryAware接口】調用setBeanFactory方法,beanFactory:{}", beanFactory.getClass().getName());
        this.beanFactory = beanFactory;
    }

    public String getBeanName() {
        return beanName;
    }

    @Override
    public void setBeanName(String beanName) {
        log.info("【BeanNameAware接口】調用setBeanName方法,name:{}", beanName);
        this.beanName = beanName;
    }

    @Override
    public void destroy() throws Exception {
        log.info("【DiposibleBean接口】調用destory方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("【InitializingBean接口】調用afterPropertiesSet方法");
    }

    public void myInit() {
        log.info("【init-method】調用<bean>的init-method屬性指定的初始化方法");
    }


    public void myDestory() {
        log.info("【destory-method】調用<bean>的destroy-method屬性指定的初始化方法");
    }

    @PostConstruct
    public void postConstruct() {
        log.info("調用@PostConstruct注解的方法");
    }

    @PreDestroy
    public void myPreDestroy() {
        log.info("調用@PreDestroy注解的方法");
    }
}
複制代碼           
package com.study.bean.lifecycle;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        log.info("InstantiationAwareBeanPostProcessorAdapter調用postProcessBeforeInstantiation方法");
        return super.postProcessBeforeInstantiation(beanClass, beanName);
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        log.info("InstantiationAwareBeanPostProcessorAdapter調用postProcessAfterInstantiation方法");
        return super.postProcessAfterInstantiation(bean, beanName);
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        log.info("InstantiationAwareBeanPostProcessorAdapter調用postProcessProperties方法,pvs:{}", JSON.toJSONString(pvs.getPropertyValues()));
        return super.postProcessProperties(pvs, bean, beanName);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("InstantiationAwareBeanPostProcessorAdapter調用postProcessBeforeInitialization方法");
        return super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("InstantiationAwareBeanPostProcessorAdapter調用postProcessAfterInitialization");
        return super.postProcessAfterInitialization(bean, beanName);
    }
}
複制代碼           
package com.study.bean.lifecycle;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("BeanPostProcessor接口調用postProcessBeforeInitialization");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("BeanPostProcessor接口調用postProcessAfterInitialization");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
複制代碼           
package com.study.bean.lifecycle;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("調用BeanFactoryPostProcessor#postProcessBeanFactory");
        BeanDefinition bd = beanFactory.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }
}
複制代碼           
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
       default-init-method="init_method" default-destroy-method="destroy_method">

    <context:component-scan base-package="com.study.bean.lifecycle"/>
    
    <bean id="person" class="com.study.bean.lifecycle.Person" init-method="myInit" destroy-method="myDestory"
          p:name="張三" p:address="廣州"
          p:phone="123567889"/>
</beans>
複制代碼           
package com.study.bean.lifecycle;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@Slf4j
public class BeanLifeCycle {
    public static void main(String[] args) {
        log.info("現在開始初始化容器");
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        log.info("容器初始化成功");
        Person person = applicationContext.getBean("person", Person.class);
        log.info("Person:{}", person);
        log.info("現在開始關閉容器");
    }
}
複制代碼           

輸出:

22:57:32.168 [main] INFO com.study.bean.lifecycle.BeanLifeCycle - 現在開始初始化容器
22:57:32.586 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7f9a81e8
22:57:33.594 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [/Users/wanghaifeng/IdeaProjects/study-java/target/classes/com/study/bean/lifecycle/MyBeanFactoryPostProcessor.class]
22:57:33.595 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [/Users/wanghaifeng/IdeaProjects/study-java/target/classes/com/study/bean/lifecycle/MyBeanPostProcessor.class]
22:57:33.596 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [/Users/wanghaifeng/IdeaProjects/study-java/target/classes/com/study/bean/lifecycle/MyInstantiationAwareBeanPostProcessor.class]
22:57:33.682 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 9 bean definitions from class path resource [beans.xml]
22:57:33.754 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
22:57:33.984 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanFactoryPostProcessor'
22:57:33.989 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
22:57:33.991 [main] INFO com.study.bean.lifecycle.MyBeanFactoryPostProcessor - 調用BeanFactoryPostProcessor#postProcessBeanFactory
22:57:33.993 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
22:57:34.010 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
22:57:34.016 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
22:57:34.027 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanPostProcessor'
22:57:34.122 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myInstantiationAwareBeanPostProcessor'
22:57:34.157 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'person'
22:57:34.158 [main] INFO com.study.bean.lifecycle.MyInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessorAdapter調用postProcessBeforeInstantiation方法,beanClass:com.study.bean.lifecycle.Person,beanName:person
22:57:34.174 [main] INFO com.study.bean.lifecycle.Person - 【構造器】調用Person的構造器執行個體化
22:57:34.184 [main] INFO com.study.bean.lifecycle.MyInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessorAdapter調用postProcessAfterInstantiation方法,bean:Person(name=null, address=null, phone=null, beanFactory=null, beanName=null),beanName:person
22:57:34.612 [main] INFO com.study.bean.lifecycle.MyInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessorAdapter調用postProcessProperties方法,pvs:[{"converted":false,"name":"address","optional":false,"originalPropertyValue":{"$ref":"@"},"value":"廣州"},{"converted":false,"name":"name","optional":false,"originalPropertyValue":{"$ref":"@"},"value":"張三"},{"converted":false,"name":"phone","optional":false,"originalPropertyValue":{"$ref":"@"},"value":"110"}]
22:57:34.752 [main] INFO com.study.bean.lifecycle.Person - [注入屬性]address:廣州
22:57:34.752 [main] INFO com.study.bean.lifecycle.Person - [注入屬性]name:張三
22:57:34.753 [main] INFO com.study.bean.lifecycle.Person - 【注入屬性】phone:110
22:57:34.753 [main] INFO com.study.bean.lifecycle.Person - 【BeanNameAware接口】調用setBeanName方法,name:person
22:57:34.753 [main] INFO com.study.bean.lifecycle.Person - 【BeanFactoryAware接口】調用setBeanFactory方法,beanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory
22:57:34.753 [main] INFO com.study.bean.lifecycle.MyBeanPostProcessor - BeanPostProcessor接口調用postProcessBeforeInitialization
22:57:34.753 [main] INFO com.study.bean.lifecycle.MyInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessorAdapter調用postProcessBeforeInitialization方法
22:57:34.753 [main] INFO com.study.bean.lifecycle.Person - 調用@PostConstruct注解的方法
22:57:34.753 [main] INFO com.study.bean.lifecycle.Person - 【InitializingBean接口】調用afterPropertiesSet方法
22:57:34.755 [main] INFO com.study.bean.lifecycle.Person - 【init-method】調用<bean>的init-method屬性指定的初始化方法
22:57:34.756 [main] INFO com.study.bean.lifecycle.MyBeanPostProcessor - BeanPostProcessor接口調用postProcessAfterInitialization
22:57:34.756 [main] INFO com.study.bean.lifecycle.MyInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessorAdapter調用postProcessAfterInitialization
22:57:34.813 [main] INFO com.study.bean.lifecycle.BeanLifeCycle - 容器初始化成功
22:57:34.815 [main] INFO com.study.bean.lifecycle.BeanLifeCycle - Person:Person(name=張三, address=廣州, phone=110, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@2805c96b: defining beans [myBeanFactoryPostProcessor,myBeanPostProcessor,myInstantiationAwareBeanPostProcessor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,person]; root of factory hierarchy, beanName=person)
22:57:34.816 [main] INFO com.study.bean.lifecycle.BeanLifeCycle - 現在開始關閉容器
22:57:34.817 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@7f9a81e8, started on Sat Apr 15 22:57:32 CST 2023
22:57:34.820 [main] INFO com.study.bean.lifecycle.Person - 調用@PreDestroy注解的方法
22:57:34.820 [main] INFO com.study.bean.lifecycle.Person - 【DiposibleBean接口】調用destory方法
22:57:34.820 [main] INFO com.study.bean.lifecycle.Person - 【destory-method】調用<bean>的destroy-method屬性指定的初始化方法

複制代碼           

圖解

Spring Bean生命周期詳解和應用(上)
  1. BeanFactoryPostProcessor#postProcessBeanFactory:在Bean被執行個體化之前,允許覆寫或者添加屬性。比如這裡對屬性phone的重新指派為110。
  2. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation:在執行個體化目标bean之前執行,如果傳回不為null那傳回的就是代理bean,可以有效的抑制target bean的預設執行個體化。
  3. 執行Person的構造器
  4. InstantiationAwareBeanPostProcessor#postAfterInstantiation:在bean被執行個體化後,在Spring屬性填充之前,執行自定義字段注入。如果傳回true屬性正常填充,傳回false跳過屬性填充還将阻止在bean執行個體上調用任何後續的InstantiationAwareBeanPostProcessor執行個體
  5. InstantiationAwareBeanPostProcessor#postProcessProperties:在工廠将給定的屬性應用于給定的bean之前對其進行後處理。
  6. 對Person的屬性進行set
  7. BeanNameAware#setBeanName:給建立的bean設定在bean工廠中的bean name。
  8. BeanFactoryAware#setBeanFactory:将擁有的工廠提供給bean執行個體的回調。
  9. BeanPostProcessor#postProcessBeforeIntialization:在bean初始化之前,可能是個代理的bean。
  10. InstantiationAwareBeanPostProcessor#postProcessorBeforeInitialization:在bean初始化之前,可能是個代理的bean。
  11. @PostConstruct:此時bean依賴已經注入完成,可以用該注解注釋的方法進行任何初始化。
  12. InitializingBen#afterProperitesSet:所有bean屬性都被設定,可以用于執行總體配置校驗和最終初始化
  13. init-method指定的方法:作為@PostConstruct和IntializingBean#afterProperitiesSet的替代方案。
  14. BeanPostProcessor#postProcessAfterInitialization:執行個體化後由BeanFactory或BeanFactory建立的對象調用
  15. InstantiationAwareBeanProcessor#postProcessAfterInitialization:執行個體化後由BeanFactory或BeanFactory建立的對象調用
  16. @PreDestory注釋的方法
  17. DispoableBean#destory
  18. destory-method指定的方法

可以大概分為十個階段:

  1. 執行構造器進行執行個體化之前的幹預:BeanFactoryPostProcessor#postProcessBeanFactory、InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
  2. 執行構造器進行執行個體化
  3. 執行個體化之後在set屬性之前的幹預:InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation、InstantuationAwareBeanPostProcessor#postProcessProperties
  4. 進行set屬性
  5. set屬性後設定beanName(BeanNameAware#setBeanName)、接收到BeanFactory的回調(BeanFactoryAware#setBeanFactory)
  6. 初始化之前的幹預:BeanPostProcessor#postBeforeInitialization、InstantionAwareBeanPostProcessor#postProcessBeforeInitialization
  7. 進行初始化:@PostConstruct、InitializingBean#afterPropertiesSet、init-method
  8. 執行個體化之後的幹預:BeanPostProcessor#postProcessAfterInitialization、InstantionAwareBeanPostProcessor#postProcessAfterInitialization
  9. 銷毀前的幹預:@preDestory
  10. 容器關閉時執行銷毀:DisposableBean#destroy、destory-method

分為四大階段,圍繞它們進行幹預:

  1. 執行個體化(Instantiation)
  2. 屬性指派(Populate)
  3. 初始化(Instialization)
  4. 銷毀(Destruction)
連結:https://juejin.cn/post/7222075996065579045