切換語言為:簡體

Spring Bean 的生命週期擴充套件

  • 爱糖宝
  • 2024-10-31
  • 2041
  • 0
  • 0

Bean 的生命週期

普通 bean 生命週期主要包含,例項化、屬性設定、資源初始化、銷燬資源等幾個階段。在不依賴於 Spring 框架的 Bean 的正常,開發人員需要針對 bean 的各個生命週期的行為進行管理和擴充套件,不夠靈活與便捷。

    Object obj = new Object();
    obj.setAttr(otherObj);
    Runtime.getRuntime().addShutdownHook(new Thread(obj::destry));

而在 Spring 中爲了更好的對 Bean 的生命週期進行管理,將 bean 劃分爲以下四個階段

  • 例項化 createBean:透過構造器或者反射獲取例項bean

  • 屬性填充 populateBean:填充 bean 的屬性及依賴注入

  • 初始化 initializeBean:執行 bean 的初始化回撥方法

  • 銷燬 destroyBean:執行bean 的銷燬回撥方法

並且針對上述的各個生命週期新增了不同的擴充套件點,例如在 bean 初始化前後回撥介面,bean 銷燬回撥介面。

生命週期擴充套件

Spring 針對bean 的生命週期定義了一系列的介面,並規定 BeanFactory 的實現需要完整支援這些 bean 的生命週期介面,下面是BeanFactory原始碼註釋中描述的 生命週期介面

1.BeanNameAware's setBeanName
2.BeanClassLoaderAware's setBeanClassLoader
3.BeanFactoryAware's setBeanFactory
4.EnvironmentAware's setEnvironment
5.EmbeddedValueResolverAware's setEmbeddedValueResolver
6.ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
7.ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
8.MessageSourceAware's setMessageSource (only applicable when running in an application context)
9.ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
10.ServletContextAware's setServletContext (only applicable when running in a web application context)
11.postProcessBeforeInitialization methods of BeanPostProcessors
12.InitializingBean's afterPropertiesSet
13.a custom init-method definition
14.postProcessAfterInitialization methods of BeanPostProcessors

On shutdown of a bean factory, the following lifecycle methods apply:

1.postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
2.DisposableBean's destroy
3.a custom destroy-method definition

針對上述生命週期擴充套件點可以劃分爲幾類

  • Aware 介面:Spring 容器會執行特定的回撥方法注入特定的Spring容器 bean,比如ClassLoader、 ApplicationContext等

  • BeanPostProcessor bean 前置處理器: bean的 初始化前後處理擴充套件,Spring內部透過該擴充套件實現了 AOP 等功能

  • init 初始化回撥:在Bean 初始化階段執行定製化回撥介面,並且提供了InitializingBean介面的回撥擴充套件,在bean 執行初始化方法執行特定邏輯

  • destroy 銷燬回撥:Spring 支援DisposableBean的介面以及自定義銷燬回撥方法,同時提供了DestructionAwareBeanPostProcessor實現在執行銷燬前的回撥介面

透過瞭解這些擴充套件點能夠幫助開發人員靈活的新增各類擴充套件以實現定製化功能。下面逐個介紹下各種型別的擴充套件以及簡單使用。

Aware 介面

Aware 介面表明 Bean 可以透過回撥的方式獲取容器中的特定的 bean 物件,子介面提供一個指定該物件型別的回撥方法。而Spring會在 實現了 Aware 介面的 Bean 例項化過程中執行相應的回撥方法,實現屬性注入。常見的 Aware 介面包括:

  • BeanNameAware: 用於獲取 bean 在容器中對應的 beanName

  • BeanClassLoaderAware: 用於獲取 例項化 bean 的 ClassLoader

  • EnvironmentAware: 獲取獲取容器執行時的 Environment 物件,該物件包含 應用執行的各類屬性配置

  • ApplicationContextAware: 獲取執行時的 ApplicationContext

  • ResourceLoaderAware: 獲取Spring的資源載入器

實現一個簡單的獲取Spring容器bean 的靜態工具類

@Service
public class SpringContextToolkit implements ApplicationContextAware {

	private static ApplicationContext ctx;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		ctx = applicationContext;
	}
	/**
	 * 透過name獲取 Bean.
	 */
	public static Object getBean(String name) {
		return getApplicationContext().getBean(name);
	}

	/**
	 * 透過class獲取Bean.
	 */
	public static <T> T getBean(Class<T> clazz) {
		return getApplicationContext().getBean(clazz);
	}
}

BeanPostProcessor Bean 前置處理器

BeanPostProcessor 介面定義了兩個回撥方法,分別在 Bean 初始化前後呼叫執行,該介面是Spring容器的核心擴充套件點,框架中很多功能都是透過該擴充套件點實現,比如 AOP 切面程式設計、事務管理等。

public interface BeanPostProcessor {

	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}
  • postProcessBeforeInitialization:在執行bean的初始化之前執行,Spring內部實現 ApplicationContextAwareProcessor透過該擴充套件功能實現了 Aware 介面的回撥方法的執行

  • postProcessAfterInitialization: 在執行bean的初始化之後執行,透過該回調方法可以對bean 進行動態代理進行方法增強,而Spring 便是透過該擴充套件實現AOP增強

透過實現該介面,開發人員可以在特定bean初始化前後進行擴充套件,比如修改屬性,新增定製化的業務邏輯。 以一個動態獲取配置中心配置的案例實現說明。bean使用配置中心註解@ConfigValue,初始化階段從遠端的配置中心獲取配置,並注入到bean屬性中。

定義註解,可以指定獲取配置中心key

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigValue {
    
    /**
     * 配置中心key
     */
    String key() default "";
}

bean 屬性新增註解,並指定獲取的配置key

@Component
public class SimpleUser {

    @ConfigValue(key = "userName")
    private String userName;
    
    ...    
}

實現 BeanPostProcessor, 在 bean 屬性使用註解時,解析屬性,並從遠端配置中心獲取配置並注入

@Component
public class ConfigValueBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> aClass = bean.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for(Field field : declaredFields){
            ConfigValue annotation = field.getAnnotation(ConfigValue.class);
            if(annotation!=null){
                String key = annotation.key();
                field.setAccessible(true);
                Object value = getConfigCenterValue(key);
                try {
                    field.set(bean,value);
                } catch (IllegalAccessException e) {

                }
            }
        }
        return bean;
    }
    private Object getConfigCenterValue(String key){
        // 從遠端配置中心獲取配置
        return "配置中心";
    }
}

上述的簡單用例就展示瞭如何透過實現BeanPostProcessor 進行bean的擴充套件,開發人員可以針對不同的業務場景進行定製化擴充套件不同的功能。

Bean 初始化

Spring在Bean 的初始化階段不僅提供了一個初始化回撥介面InitializingBean ,同時支援指定自定義初始化方法init-method

  • bean初始化回撥:

    • InitializingBean :初始化生命週期介面,Spring 會在bean的所有屬性都設定完成後,呼叫 afterPropertiesSet 方法完成最後的初始化操作

    • init-method : 在Spring完成Bean的初始化後,執行指定自定義的一些初始化方法。註解方式可以透過 @Bean註解的initMethod指定回撥方法名

透過初始化回撥的執行方法可以進行bean的合法性校驗並完成最終初始化操作。

Bean 的銷燬

在Bean的銷燬階段Spring 不僅提供了DisposableBean的介面回撥和定製化銷燬方法回撥,另外提供了DestructionAwareBeanPostProcessors 的前置回撥介面。該類是BeanPostProcessor的子介面,並且提供了postProcessBeforeDestruction的擴充套件方法,在執行銷燬動作前完成特定邏輯。

  • bean的銷燬回撥:

    • DestructionAwareBeanPostProcessors : DestructionAwareBeanPostProcessors是Bean 在銷燬階段的後置處理器介面,用於在Bean的銷燬階段回撥執行。

    • DisposableBean:bean的銷燬生命週期介面,透過實現該介面destroy方法完成最終的銷燬邏輯,比如資源的釋放和銷燬

    • destroy-method:對應init-method ,Spring最後執行自定義的銷燬方法 。註解方式可以透過 @Bean註解的destroyMethod指定回撥方法名

以上的幾類介面和方法是Spring為開發人員針對Bean的生命週期管理提供的擴充套件點,開發人員可以透過這些擴充套件點對bean進行管理與增強。而Spring內部也存在特定的擴充套件介面,用於Spring框架基礎功能的實現。

Spring 的內部生命週期擴充套件

上述 bean 的生命週期擴充套件方法開發人員可以根據各自的業務場景進行選擇靈活實現,而Spring 框架內部在實現框架功能時定義了一些內部擴充套件,這些擴充套件主要是爲了框架內部服務,並不建議開發人員使用,可以做一個簡單的瞭解

InstantiationAwareBeanPostProcessor

注意:Instantiation(例項化),指bean的建立過程。Initialization (初始化),指bean的初始化過程,這時bean已建立但未完全裝配完成。

Bean例項化後置處理器,該介面在BeanPostProcessor的基礎上額外擴充套件了三個回撥方法,分別在Bean的例項化與屬性填充階段執行。

  • postProcessBeforeInstantiation在 Bean 執行例項化前回調,可以透過該方法返回一個代理物件替換真實要獲取的物件,例如Spring AOP元件類AbstractAutoProxyCreator實現了該方法進行代理。

  • postProcessAfterInstantiation在Bean 已建立但是屬性未完成資料填充階段執行回撥,決定是否繼續進行後續的初始化操作。

  • postProcessProperties可實現對Bean的屬性填充或者替換修改,Spring內部實現類AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor 對新增了 @Autowired@Value@Resource等註解的屬性進行資料填充。

該介面其實還有一個postProcessPropertyValues回撥方法,其作用與postProcessProperties方法一致,並且被標註未廢棄。所以一般推薦使用postProcessProperties方法

SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor 擴充套件了 InstantiationAwareBeanPostProcessor 介面 提供了更多的自定義例項化控制方法。它允許你在bean例項化過程中進行更細粒度的控制,特別是關於目標型別的預測和方法重寫。Spring 主要透過該介面實現了AOP 動態代理,

  • predictBeanType: 此方法主要用於預測 Bean 的型別。當透過 Bean 名稱無法確定其型別時,此方法被呼叫。它在實際 Bean 例項化之前提供了一種機制來推斷 Bean 的型別。

  • determineCandidateConstructors:確定用於例項化bean的候選建構函式。如果返回 null 或空陣列,Spring將使用預設的建構函式選擇邏輯。

  • getEarlyBeanReference: 該方法在 Bean 例項化後、初始化前被呼叫,主要用於解決迴圈依賴的問題,它允許在完全初始化之前暴露 Bean 的早期引用。

迴圈依賴問題即兩個或多個Bean存在互相依賴的關係,例如容器在例項化 beanA 的過程中發現依賴於 beanB ,然後去嘗試例項化 beanB 的過程中發現又需要依賴於 beanA ,這種場景就被稱作迴圈依賴。


作者:withelios
連結:https://juejin.cn/post/7431754032450289673


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.