成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

強大!牢記這16個Spring Boot擴展接口,代碼優雅提升一個層次

開發 前端
當 ApplicationContext 初始化或刷新時發布此事件。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法時發生。這里的初始化是指所有Beans成功加載、后置處理器Beans被檢測并激活、所有單例Beans被預實例化,并且 ApplicationContext 容器已準備好使用。

Spring的核心理念是它的容器。當容器刷新時,表面看似風平浪靜,內部卻如同風起云涌的大海,廣闊而洶涌。SpringBoot更進一步,將Spring封裝起來,遵循“約定優于配置”的原則,并結合自動配置機制。通常情況下,只需添加一個依賴,我們就能以最小配置甚至零配置實現功能。

我尤其喜歡自動配置機制,因此在開發中間件和通用依賴工具時經常使用這個功能。這種方法允許用戶以最低的成本進行集成。要掌握自動配置,必須了解Spring Bean的構建生命周期以及各種擴展接口。當然,理解Bean的不同生命周期也能幫助更深入地理解Spring,業務代碼也可以合理地利用這些擴展點編寫更加優雅的代碼。

在本文中,我總結了幾乎所有Spring和SpringBoot的擴展接口及其應用場景。同時,我整理了Bean從加載到最終初始化過程中所有可擴展點的時序圖,這使我們能夠一窺Bean是如何逐步加載到Spring容器中的。

文章內容較長,請耐心閱讀!

啟動期間可擴展接口調用的時序圖

以下是Bean在Spring容器中的生命周期中所有可擴展點的順序圖。

接下來我將逐一分析每一個。

圖片圖片

ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

這是一個用于在整個Spring容器刷新之前初始化ConfigurableApplicationContext的回調接口。簡單來說,在容器刷新之前,會調用該類的initialize方法,此時允許用戶擴展。用戶可以在整個Spring容器初始化之前做一些事情。

可能的使用場景包括在最初激活某些配置,或利用類加載器加載類之前的時機執行如動態字節碼注入等操作。

擴展方法如下:

public class TestApplicationContextInitializer implements ApplicationContextInitializer {      
    @Override      
    public void initialize(ConfigurableApplicationContext applicationContext) {      
        System.out.println("[ApplicationContextInitializer]");      
    }      
}

由于此時Spring容器尚未初始化,因此有三種方式使你的擴展生效:

  • 在啟動類中添加springApplication.addInitializers(new TestApplicationContextInitializer())。
  • 在配置文件中設置context.initializer.classes=com.example.demo.TestApplicationContextInitializer。
  • 使用Spring的SPI擴展,在spring.factories中添加org.springframework.context.Applicatinotallow=com.example.demo.TestApplicationContextInitializer。

BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

該接口是在讀取項目中的beanDefinition后執行的,提供了一個補充的擴展點。

使用場景:你可以在此處動態注冊自定義的beanDefinition,并加載類路徑之外的Bean。

擴展方法如下:

public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {      
    @Override      
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {      
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");      
    }      
      
    @Override      
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");      
    }      
}

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

該接口是對beanFactory的擴展,它的調用發生在Spring讀取完beanDefinition信息之后,Bean實例化之前。

在這個階段,用戶可以通過實現該擴展接口來處理某些任務,如修改已注冊的beanDefinition的元數據。

擴展方法如下:

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {      
    @Override      
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println("[BeanFactoryPostProcessor]");      
    }      
}

InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

此接口繼承自BeanPostProcessor接口,區別在于:

BeanPostProcessor接口只在Bean的初始化階段(即注入Spring上下文之前和之后)擴展,而InstantiationAwareBeanPostProcessor接口增加了三個方法,擴展了Bean的實例化和屬性注入階段的作用范圍。

該類的主要擴展點是以下五個方法,它們在Bean生命周期的實例化階段和初始化階段發揮作用。按調用順序如下:

  • postProcessBeforeInstantiation: 在實例化Bean之前,相當于在創建(new)Bean之前。
  • postProcessAfterInstantiation: 在實例化Bean之后,相當于創建(new)Bean之后。
  • postProcessPropertyValues: Bean實例化后,在屬性注入階段觸發。像@Autowired、@Resource等注解的原理就基于這個方法。
  • postProcessBeforeInitialization: Bean初始化之前,相當于在Bean注入Spring上下文之前。
  • postProcessAfterInitialization: Bean初始化之后,相當于在Bean注入Spring上下文之后。

使用場景:該擴展點在中間件開發和業務邏輯中都非常有用。例如,可以在Bean生命周期的不同階段收集實現某個接口的Bean,或為某種類型的Bean統一設置屬性等。

擴展方法如下:

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);      
        return bean;      
    }      
      
    @Override      
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);      
        return bean;      
    }      
      
    @Override      
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);      
        return null;      
    }      
      
    @Override      
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);      
        return true;      
    }      
      
    @Override      
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);      
        return pvs;      
    }

SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

該擴展接口有三個觸發方法:

  • predictBeanType: 在postProcessBeforeInstantiation之前觸發(在時序圖中未標出,通常不需要擴展此點)。該方法用于預測Bean的類型,返回第一個成功預測的Class類型,如果無法預測則返回null。當調用BeanFactory.getType(name)且無法通過Bean名稱確定類型信息時,該回調方法用于決定類型信息。
  • determineCandidateConstructors: 在postProcessBeforeInstantiation之后觸發,用于確定Bean的構造函數,返回Bean的所有構造函數列表。用戶可以擴展此點以自定義選擇適當的構造函數來實例化Bean。
  • getEarlyBeanReference: 在postProcessAfterInstantiation之后觸發。在存在循環依賴的場景下,Bean實例化后,為了防止循環依賴,提前暴露回調方法,用于實例化后的Bean進行后處理。

擴展方法如下:

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);      
        return beanClass;      
    }      
      
    @Override      
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);      
        return null;      
    }      
      
    @Override      
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);      
        return bean;      
    }      
}

BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

此類只有一個觸發點,即在Bean實例化后、屬性注入之前(即Setter方法之前)觸發。該類的擴展點方法是setBeanFactory,當用戶想要獲取當前BeanFactory的引用時,可以擴展此接口來獲取。

擴展方法如下:

public class TestBeanFactoryAware implements BeanFactoryAware {      
    @Override      
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {      
        System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());      
    }      
}

ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

雖然這個類本身沒有擴展點,但它內部提供了六個擴展點用于實現。這些擴展點是在bean實例化后、初始化之前觸發的。

圖片圖片

正如你所看到的,這個類用于在bean實例化并填充屬性之后執行各種驅動接口。通過執行上述突出顯示的擴展接口,可以獲得相應的容器變量。因此,這里實際上有六個擴展點,我將一起討論:

  • EnvironmentAware: 用于獲取 EnvironmentAware 的擴展類。這個變量非常有用,可以訪問系統中的所有參數。個人認為,沒必要擴展這個 Aware,因為Spring內部已經支持通過注入直接獲取。
  • EmbeddedValueResolverAware: 用于獲取 StringValueResolver 的擴展類。StringValueResolver 用于獲取基于字符串的屬性變量。通常我們使用 @Value 注解獲取這些變量,但如果實現了這個 Aware 接口并緩存 StringValueResolver,就可以使用它來獲取基于字符串的變量,效果相同。
  • ResourceLoaderAware: 用于獲取 ResourceLoader 的擴展類。ResourceLoader 可以訪問類路徑中的所有資源對象。你可以擴展這個類來獲取 ResourceLoader 對象。
  • ApplicationEventPublisherAware: 用于獲取 ApplicationEventPublisher 的擴展類。ApplicationEventPublisher 用于發布事件,通常與 ApplicationListener 結合使用,我將在后面詳細介紹。此對象也可以通過Spring注入獲得。
  • MessageSourceAware: 用于獲取 MessageSource 的擴展類。MessageSource 主要用于國際化。
  • ApplicationContextAware: 用于獲取 ApplicationContext 的擴展類。許多人都熟悉 ApplicationContext,它是Spring的上下文管理器,允許手動訪問Spring上下文中注冊的任何bean。我們經常擴展這個接口來緩存Spring上下文,并將其包裝成靜態方法。此外,ApplicationContext 還實現了 BeanFactory、MessageSource、ApplicationEventPublisher 等接口,可以用于相關任務。

BeanNameAware

org.springframework.beans.factory.BeanNameAware

可以看出,這個類也是一種 Aware 擴展。其觸發點發生在bean初始化之前,即 postProcessBeforeInitialization 之前。這個類只有一個觸發點方法:setBeanName。

使用場景:用戶可以擴展此點,在初始化bean之前獲取Spring容器中注冊的beanName,然后根據需要修改這個beanName的值。

擴展方法:

public class NormalBeanA implements BeanNameAware{      
    public NormalBeanA() {      
        System.out.println("NormalBean constructor");      
    }      
      
    @Override      
    public void setBeanName(String name) {      
        System.out.println("[BeanNameAware] " + name);      
    }      
}

@PostConstruct

javax.annotation.PostConstruct

這不是一個擴展點,而是一種標記。它的作用是在bean初始化階段。如果某個方法被 @PostConstruct 注解標記,那么該方法將首先被調用。需要注意的是,這個標準的具體觸發點是在 postProcessBeforeInitialization 之后、InitializingBean.afterPropertiesSet 之前。

使用場景:用戶可以通過注解特定方法來初始化某個特定屬性。

擴展方法:

public class NormalBeanA {      
    public NormalBeanA() {      
        System.out.println("NormalBean constructor");      
    }      
      
    @PostConstruct      
    public void init(){      
        System.out.println("[PostConstruct] NormalBeanA");      
    }      
}

InitializingBean

org.springframework.beans.factory.InitializingBean

顧名思義,這個類也用于bean的初始化。InitializingBean 接口為bean提供了一個初始化方法,它只有一個方法 afterPropertiesSet。任何繼承此接口的類將在bean初始化過程中執行此方法。此擴展的觸發點在 postProcessAfterInitialization 之前。

使用場景:用戶可以實現此接口,在系統啟動時初始化某些業務指標。

擴展方法:

public class NormalBeanA implements InitializingBean{      
    @Override      
    public void afterPropertiesSet() throws Exception {      
        System.out.println("[InitializingBean] NormalBeanA");      
    }      
}

FactoryBean

org.springframework.beans.factory.FactoryBean

在正常情況下,Spring使用反射機制和bean的類屬性來實例化bean。但在某些情況下,bean的實例化過程可能非常復雜,如果按照傳統方式進行,則需要在bean中配置大量信息,配置方法的靈活性有限。在這種情況下,編碼的方式可能會更簡單。為此,Spring提供了 org.springframework.beans.factory.FactoryBean 接口,允許用戶自定義bean實例化的邏輯。

FactoryBean 接口在Spring框架中具有重要地位。Spring自身提供了超過70種 FactoryBean實現,它們隱藏了某些復雜bean實例化的細節,給高級應用帶來了方便。從Spring 3.0開始,FactoryBean 支持泛型,接口聲明變為 FactoryBean<T>。

使用場景:用戶可以擴展此類,為他們希望實例化的bean創建代理。例如,他們可以攔截對象的所有方法,在每次調用之前和之后輸出一行日志,模擬 ProxyFactoryBean 的功能。

擴展方法:

public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {      
      
    @Override      
    public TestFactoryBean.TestFactoryInnerBean getObject() throws Exception {      
        System.out.println("[FactoryBean] getObject");      
        return new TestFactoryBean.TestFactoryInnerBean();      
    }      
      
    @Override      
    public Class<?> getObjectType() {      
        return TestFactoryBean.TestFactoryInnerBean.class;      
    }      
      
    @Override      
    public boolean isSingleton() {      
        return true;      
    }      
      
    public static class TestFactoryInnerBean{      
      
    }      
}

SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

這個接口只有一個方法 afterSingletonsInstantiated,其目的是作為回調接口,在Spring容器管理的所有單例對象(非延遲加載對象)初始化后調用。它的觸發點是在 postProcessAfterInitialization 之后。

使用場景:用戶可以擴展此接口,在所有單例對象完全初始化后執行一些后處理業務。

擴展方法:

public class TestSmartInitializingSingleton implements SmartInitializingSingleton {      
    @Override      
    public void afterSingletonsInstantiated() {      
        System.out.println("[TestSmartInitializingSingleton]");      
    }      
}

CommandLineRunner

org.springframework.boot.CommandLineRunner

這個接口也只有一個方法:run(String... args)。它的觸發點是在整個項目啟動之后,自動執行。如果有多個 CommandLineRunner 實例,可以使用 @Order 注解進行排序。

使用場景:用戶可以擴展此接口,在項目啟動后進行一些業務預處理。

擴展方法:

public class TestCommandLineRunner implements CommandLineRunner {      
      
    @Override      
    public void run(String... args) throws Exception {      
        System.out.println("[TestCommandLineRunner]");      
    }      
}

** DisposableBean**

org.springframework.beans.factory.DisposableBean

這個擴展點也只有一個方法:destroy()。它的觸發點是在對象被銷毀時,自動執行此方法。例如,當運行 applicationContext.registerShutdownHook 時,此方法將被觸發。

擴展方法:

public class NormalBeanA implements DisposableBean {      
    @Override      
    public void destroy() throws Exception {      
        System.out.println("[DisposableBean] NormalBeanA");      
    }      
}

ApplicationListener

org.springframework.context.ApplicationListener

嚴格來說,這不應被視為Spring & Spring Boot中的擴展點。ApplicationListener 可以監聽特定的事件 (event)。觸發時機可以穿插在業務方法執行過程中,允許用戶定義自己的業務事件。

然而,Spring內部有一些內置事件。這些事件可以與啟動過程交織在一起。我們也可以利用此功能,為這些內置事件創建自己的監聽器,達到與之前某些觸發點類似的效果。

讓我們列出Spring中的一些主要內置事件:

  • ContextRefreshedEvent: 當 ApplicationContext 初始化或刷新時發布此事件。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法時發生。這里的初始化是指所有Beans成功加載、后置處理器Beans被檢測并激活、所有單例Beans被預實例化,并且 ApplicationContext 容器已準備好使用。
  • ContextStartedEvent : 當使用ConfigurableApplicationContext(ApplicationContext的子接口)中的start()方法啟動ApplicationContext時發布此事件。在spring中,您可以使用start()和stop()方法控制ApplicationContext的生命周期。啟動容器后,可以通過stop()停止容器。當容器啟動時,您可以通過getLifecycle()方法獲取所有Lifecycle接口的Bean,并激活它們的start() 方法。這通常用于具有后臺任務的Bean。
  • ContextStoppedEvent : 與 ContextStartedEvent 相反,stop() 方法會觸發 ContextStoppedEvent 事件。
  • ContextClosedEvent: 當使用 ConfigurableApplicationContext 中的 close() 方法關閉 ApplicationContext 時,發布此事件。關閉的上下文 context 不會被重新啟動或刷新。
  • RequestHandledEvent: Web應用程序中特有的事件。它表示Web請求的完成(只有在使用Spring的 DispatcherServlet 時才適用)。
  • ApplicationFailedEvent: 該事件在啟動Spring Boot時遇到異常時觸發。

總結

通過這些 Spring 和 Spring Boot 的擴展點,我們可以大致了解一個 bean 的整個生命周期。在業務開發或中間件業務編寫過程中,我們可以合理利用 Spring 提供的擴展點,在 Spring 啟動的各個階段執行特定操作,從而實現自定義初始化的目的。

責任編輯:武曉燕 來源: 路條編程
相關推薦

2023-09-25 13:06:36

SpringBoot擴展接口

2024-01-22 09:01:00

SpringBoot接口代碼

2022-06-06 08:42:04

spring-boo開發接口防盜刷

2020-03-16 17:20:02

異常處理Spring Boot

2024-07-25 14:36:10

2022-06-21 14:44:38

接口數據脫敏

2024-11-07 10:55:26

2024-11-08 15:56:36

2020-06-22 07:55:28

接口爬蟲

2023-08-01 08:54:02

接口冪等網絡

2025-02-23 08:00:00

冪等性Java開發

2020-11-13 07:08:51

Spring Boot應用Spring

2020-09-15 11:40:37

Spring Boot代碼Java

2022-12-12 08:14:47

2013-08-01 15:12:43

2020-09-27 14:13:50

Spring BootJava框架

2015-03-30 12:20:07

DemoStoryboard

2024-02-19 08:26:59

wxPython界面庫開發

2024-11-06 11:33:09

2025-03-26 00:35:00

Javaweb開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区亚洲视频 | 黄色毛片在线观看 | 精产嫩模国品一二三区 | 欧美一级电影免费观看 | 二区三区av| 四虎在线观看 | 国产日韩欧美一区二区 | 99精品视频一区二区三区 | 日韩在线视频观看 | 精品欧美一区二区三区 | 日本不卡视频在线播放 | 国产亚洲欧美在线 | 亚洲成av人影片在线观看 | 天堂色网| 日韩欧美一区二区三区免费看 | 日韩精品一区二区三区中文在线 | 欧美激情久久久 | 午夜欧美一区二区三区在线播放 | 日韩在线中文 | 日韩电影免费在线观看中文字幕 | 精品国产一区二区三区日日嗨 | 91精品久久久久久久久中文字幕 | 一区二区三区四区在线 | 日韩午夜电影在线观看 | 欧美色综合| 九九热在线精品视频 | 久久久成人网 | 精精国产xxxx视频在线播放 | 天天操夜夜爽 | 国产精品爱久久久久久久 | 91亚洲精品国偷拍自产在线观看 | 午夜激情在线视频 | 少妇一级淫片免费放播放 | 欧美人妇做爰xxxⅹ性高电影 | 人人看人人草 | 欧美激情五月 | 国产视频一区在线观看 | 成人在线观 | 国产精品视频一 | 一区二区三区四区在线免费观看 | 欧美一级片黄色 |