寫在前面 Spring的核心思想就是容器,當容器refresh的時候,外部看上去風平浪靜,其實內部則是一片驚濤駭浪,汪洋一片。Springboot更是封裝了Spring,遵循約定大於配置,加上自動裝配的機制。很多時候我們只要引用了一個依賴,幾乎是零配置就能完成一個功能的裝配。 由spring提供的、 ...
寫在前面
Spring的核心思想就是容器,當容器refresh的時候,外部看上去風平浪靜,其實內部則是一片驚濤駭浪,汪洋一片。Springboot更是封裝了Spring,遵循約定大於配置,加上自動裝配的機制。很多時候我們只要引用了一個依賴,幾乎是零配置就能完成一個功能的裝配。
由spring提供的、在容器或bean生命周期各個階段、供spring框架回調使用的函數方法,即為擴展點。擴展點體現了Spring框架的靈活性、業務親和性。使開發人員可以在不修改spring源碼的情況下,對容器和bean的行為、屬性進行額外的管理。
想要把自動裝配玩的轉,就必須要瞭解spring對於bean的構造生命周期以及各個擴展介面,當然瞭解了bean的各個生命周期也能促進我們加深對spring的理解。業務代碼也能合理利用這些擴展點寫出更優雅的代碼。
在網上搜索spring擴展點,發現很少有博文說的很全的,只有一些常用的擴展點的說明。所以在這篇文章里,我總結了幾乎Spring & Springboot所有的擴展介面,各個擴展點的使用場景,並整理出一個bean在spring中從被載入到初始化到銷毀的所有可擴展點的順序調用圖。
本文不講原理,只將擴展點與使用方式講清楚,特別是調用順序,原理可以移步IOC系列文章,Bean的生命周期,後續會不斷更新對應原理及源碼解析。大家可以把這篇文章當成一個工具書,當忘了執行順序時,或者忘瞭如何使用這個擴展方式時,可以再回過頭來看看。
ApplicationContextInitializer
org.springframework.context.ApplicationContextInitializer
介紹
這是整個spring容器在刷新之前初始化ConfigurableApplicationContext
的回調介面,簡單來說,就是在容器刷新refresh之前調用 此類的initialize
方法。這個介面的主要目的是在 Spring 應用上下文初始化的早期階段進行一些配置或調整,以便在上下文載入後可以使用這些配置。
此介面,Spring Framework
自己沒有提供任何的實現類,但在SpringBoot
對它有較多的擴展實現。
使用場景
- 在應用啟動時進行環境配置:可以使用
ApplicationContextInitializer
來在應用上下文初始化時進行一些環境相關的配置,例如設置系統屬性、載入外部配置文件等。
public class EnvironmentInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.setActiveProfiles("development");
System.out.println("配置文件設置為development");
}
}
- 註冊自定義的
BeanFactoryPostProcessor
或者BeanPostProcessor
:ApplicationContextInitializer
可以用來註冊自定義的BeanFactoryPostProcessor
或者BeanPostProcessor
,以便在 Bean 初始化之前或之後進行某些自定義處理。
public class CustomBeanFactoryPostProcessorInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
// 添加自定義的 BeanFactoryPostProcessor
System.out.println("添加了自定義BeanFactory後處理器...");
});
}
}
- 動態地添加
PropertySource
:可以在初始化過程中動態地添加PropertySource
,以便後續的 Bean 定義和初始化過程中可以使用這些屬性。
public class PropertySourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
propertySources.addFirst(new MapPropertySource("customPropertySource", Collections.singletonMap("customKey", "customValue")));
System.out.println("已添加自定義屬性源");
}
}
Spring環境下添加擴展點
在Spring環境下自定義實現一個ApplicationContextInitializer
讓並且它生效的方式有三種:
- 手動調用的setXXX方法添加
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
// Add initializer
context.addApplicationListener(new TestApplicationContextInitializer());
// Set config locations and refresh context
context.setConfigLocation("classpath:applicationContext.xml");
context.refresh();
// Use the context
// ...
context.close();
- Spring 的 XML 配置文件中註冊
<context:initializer class="com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer"/>
- web.xml 文件配置
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer</param-value>
</context-param>
SpringBoot環境下添加擴展點
示例,展示瞭如何實現一個ApplicationContextInitializer來添加一個自定義的屬性源:
public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
// 創建自定義的屬性源
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("custom.property", "custom value");
MapPropertySource customPropertySource = new MapPropertySource("customPropertySource", customProperties);
// 將自定義屬性源添加到應用程式上下文的屬性源列表中
propertySources.addFirst(customPropertySource);
}
}
在SpringBoot中讓它生效的方式也有三種:
- 在啟動類中用
springApplication.addInitializers(new TestApplicationContextInitializer())
語句加入
@SpringBootApplication
public class MySpringExApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MySpringExApplication.class);
application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
application.run(args);
}
}
- application配置文件 配置
com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
# application.yml文件
context:
initializer:
classes: com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
- Spring SPI擴展,在spring.factories中加入(官方推薦):
com.seven.springsrpingbootextentions.extentions.TestApplicationContextInitializer
SpringBoot內置的ApplicationContextInitializer
-
DelegatingApplicationContextInitializer:使用環境屬性
context.initializer.classes
指定的初始化器(initializers)進行初始化工作,如果沒有指定則什麼都不做。通過它使得我們可以把自定義實現類配置在application.properties
里成為了可能。 -
ContextIdApplicationContextInitializer:設置Spring應用上下文的ID,Id設置為啥值會參考環境屬性:
- spring.application.name
- vcap.application.name
- spring.config.name
- spring.application.index
- vcap.application.instance_index
- 如果這些屬性都沒有,ID使用application。
-
ConfigurationWarningsApplicationContextInitializer:對於一般配置錯誤在日誌中作出警告
-
ServerPortInfoApplicationContextInitializer:將內置servlet容器實際使用的監聽埠寫入到Environment環境屬性中。這樣屬性
local.server.port
就可以直接通過@Value
註入到測試中,或者通過環境屬性Environment獲取。 -
SharedMetadataReaderFactoryContextInitializer:創建一個 SpringBoot 和 ConfigurationClassPostProcessor 共用的 CachingMetadataReaderFactory對象。實現類為:ConcurrentReferenceCachingMetadataReaderFactory
-
ConditionEvaluationReportLoggingListener:將ConditionEvaluationReport寫入日誌。
BeanFactoryPostProcessor
org.springframework.beans.factory.config.BeanFactoryPostProcessor
介紹
這個介面是beanFactory
的擴展介面,調用時機在spring在讀取beanDefinition
信息之後,實例化bean之前。雖然此時不能再註冊beanDefinition,但是可以趁著bean沒有實例化,可以修改 Spring 容器啟動時修改其內部的 BeanDefinition
。通過實現 BeanFactoryPostProcessor
介面,開發者可以在 Bean 實例化之前修改 Bean 的定義元數據,例如Scope、依賴查找方式、初始化方法、修改屬性值、添加額外的元數據等,進而影響初始化行為。
在應用程式啟動時,Spring容器會自動檢測並調用所有實現了BeanFactoryPostProcessor介面的類的postProcessBeanFactory方法。開發人員可以利用這個方法來實現自定義的邏輯,從而實現一些高級的自定義邏輯和功能擴展。此方法只調用一次,同時記住不要在這裡做Bean的實例化。
使用場景
- 修改 Bean 屬性:可以動態地改變某些配置屬性或者註入額外的依賴。
public class PropertyModifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.addPropertyValue("propertyName", "newValue");
}
}
- 動態註冊 Bean:可以根據配置文件或者系統環境變數來決定是否註冊某個 Bean。
public class ConditionalBeanRegistrar implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (someCondition()) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyBean.class);
beanFactory.registerBeanDefinition("myConditionalBean", beanDefinitionBuilder.getBeanDefinition());
}
}
private boolean someCondition() {
// 自定義條件邏輯
return true;
}
}
- 修改 Bean 定義:可以修改 Bean 的作用域、初始化和銷毀方法等定義信息。
public class ScopeModifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
}
- 屬性占位符替換:可以使用
PropertyPlaceholderConfigurer
實現BeanFactoryPostProcessor
介面,來替換 Bean 定義中的屬性占位符。
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
throws BeansException {
super.processProperties(beanFactory, props);
// 自定義屬性處理邏輯
}
}
其它使用場景:
- 配置中心集成:當需要從外部配置中心(如 Spring Cloud Config 或 Apache Zookeeper)動態載入配置並修改 Bean 定義時,可以使用
BeanFactoryPostProcessor
。 - 多環境支持:根據不同的環境(如開發、測試、生產環境)動態修改 Bean 的定義,確保不同環境下的 Bean 配置有所不同。
- 動態註冊 Bean:在應用運行時,根據條件動態註冊或者取消 Bean,比如在某些特定條件下才需要註冊某些 Bean。
- 複雜業務應用:有時候會需要根據複雜的業務規則動態調整 Bean 的配置,這時候
BeanFactoryPostProcessor
非常有用。
BeanDefinitionRegistryPostProcessor
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
介紹
BeanDefinitionRegistryPostProcessor為容器級後置處理器。容器級的後置處理器會在Spring容器初始化後、刷新前執行一次,用於動態註冊Bean到容器。
通過 BeanFactoryPostProcessor 的子類 BeanDefinitionRegistryPostProcessor,可以註冊一個你自己的BeanDefinition對象到容器中,等待容器內部依次調用進行對象實例化就能當bean用了。
BeanDefinitionRegistryPostProcessor用於在bean解析後實例化之前通過BeanDefinitionRegistry對BeanDefintion進行增刪改查。
前文介紹的BeanFactoryPostProcessor是這個介面的父類,因此實現BeanDefinitionRegistryPostProcessor這個介面,也可以重寫其父類。但實現了BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法會先執行,再執行實現了BeanFactoryPostProcessor的postProcessBeanFactory。具體看調用順序圖
使用場景
- 修改現有的 BeanDefinition:可以在 Bean 實例化之前修改現有的
BeanDefinition
,如更改其屬性值或作用域。
public class BeanDefinitionModifier implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中修改現有的 BeanDefinition");
if (registry.containsBeanDefinition("myExistingBean")) {
BeanDefinition beanDefinition = registry.getBeanDefinition("myExistingBean");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.add("propertyName", "newValue");
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用於進一步處理
}
}
- 條件性地註冊 Bean:基於某些條件(如環境變數、配置文件等)動態註冊或取消註冊某些 Bean。
public class ConditionalBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中根據條件註冊 Bean");
if (someCondition()) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(ConditionalBean.class)
.getBeanDefinition();
registry.registerBeanDefinition("conditionalBean", beanDefinition);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用於進一步處理
}
private boolean someCondition() {
// 自定義條件邏輯
return true;
}
}
- 掃描和註冊自定義註解的 Bean:實現自定義註解的掃描邏輯,並動態註冊這些註解標註的 Bean。
public class CustomAnnotationBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中掃描並註冊自定義註解的 Bean");
// 自定義掃描邏輯,假設找到一個類 MyAnnotatedBean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MyAnnotatedBean.class)
.getBeanDefinition();
registry.registerBeanDefinition("myAnnotatedBean", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用於進一步處理
}
}
- 比如依賴Redis.jar,如果該依賴jar存在,則用redis當緩存,否則就用本地緩存。這個需求完全可以在postProcessBeanDefinitionRegistry中利用Class.forName判斷依賴,存在的話則註冊對應class到容器。
@Configuration
public class AppConfig {
@Bean
public static BeanDefinitionRegistryPostProcessor customBeanDefinitionRegistryPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("在 postProcessBeanDefinitionRegistry 中根據條件註冊緩存實現類");
try {
// 檢查 Redis 依賴是否存在
Class.forName("redis.clients.jedis.Jedis");
System.out.println("檢測到 Redis 依賴,註冊 RedisCacheService");
AbstractBeanDefinition redisCacheBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(RedisCacheService.class)
.getBeanDefinition();
registry.registerBeanDefinition("cacheService", redisCacheBeanDefinition);
} catch (ClassNotFoundException e) {
System.out.println("未檢測到 Redis 依賴,註冊 LocalCacheService");
AbstractBeanDefinition localCacheBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(LocalCacheService.class)
.getBeanDefinition();
registry.registerBeanDefinition("cacheService", localCacheBeanDefinition);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用於進一步處理
}
};
}
}
- Mybatis就是用BeanFactoryPostProcessor去註冊的mapper
MapperScannerConfigurer
的主要功能是通過掃描指定的包路徑,找到所有標註了 @Mapper
註解(或其他指定註解)的介面,並將這些介面註冊為 Spring 的 BeanDefinition。這樣,Spring 容器在啟動時會自動創建這些 Mapper 介面的代理對象,並將其註入到需要的地方。
以下是 MapperScannerConfigurer
的核心代碼片段:
// org.mybatis.spring.mapper.MapperScannerConfigurer#postProcessBeanDefinitionRegistry
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private String basePackage;
private ApplicationContext applicationContext;
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
//設置其資源載入器為當前的 ApplicationContext
scanner.setResourceLoader(this.applicationContext);
scanner.registerFilters();
//調用 scanner.scan(this.basePackage) 方法,掃描指定的包路徑,找到所有符合條件的 Mapper 介面,並將它們註冊為 Spring 的 BeanDefinition。
scanner.scan(this.basePackage);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法可以留空或用於進一步處理
}
}
BeanPostProcessor
org.springframework.beans.factory.config.BeanPostProcessor
介紹
BeanPostProcessor
介面定義了兩個基本的Bean初始化回調方法,在屬性賦值前後執行。
postProcessBeforeInitialization
:在 Bean 初始化方法(如@PostConstruct
、InitializingBean.afterPropertiesSet
或自定義初始化方法)調用之前執行;返回的對象將是實際註入到容器中的 Bean,如果返回 null,則該 Bean 不會被註冊。可用於創建代理類postProcessAfterInitialization
:初始化bean之後,返回的對象將是實際註入到容器中的 Bean,如果返回 null,則該 Bean 不會被註冊。
使用場景
- 初始化前後進行自定義邏輯:在 Bean 初始化之前或之後執行一些自定義的操作,例如設置一些屬性、進行依賴註入、執行某些檢查等。
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("bean初始化前: " + beanName);
((MyBean) bean).setName("Modified Name Before Initialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("bean初始化後: " + beanName);
}
return bean;
}
}
public class MyBean {
private String name;
public MyBean(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void init() {
System.out.println("bean正在init: " + name);
}
@Override
public String toString() {
return "MyBean{name='" + name + "'}";
}
- 代理對象的生成:在
postProcessAfterInitialization
方法中生成 Bean 的代理對象,用於 AOP(面向切麵編程)或其他用途。
@Component
public class ProxyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
});
return enhancer.create();
}
return bean;
}
}
- 日誌記錄和監控:記錄 Bean 的初始化過程,進行性能監控、日誌記錄等。
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("開始初始化bean: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean結束: " + beanName);
return bean;
}
}
- 自動裝配和註入:在初始化前後進行自動裝配和註入,例如通過反射為某些欄位註入值。
@Component
public class AutowireBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(AutowireCustom.class)) {
field.setAccessible(true);
try {
field.set(bean, "Injected Value");
} catch (IllegalAccessException e) {
throw new BeansException("Failed to autowire field: " + field.getName(), e) {};
}
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface AutowireCustom {
}
public class MyBean {
@AutowireCustom
private String customField;
public MyBean() {
}
@Override
public String toString() {
return "MyBean{customField='" + customField + "'}";
}
}
InstantiationAwareBeanPostProcessor
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
介紹
該介面繼承了BeanPostProcessor
介面,因為InstantiationAwareBeanPostProcessor也屬於Bean級的後置處理器,區別如下:
BeanPostProcess
介面只在bean的初始化階段進行擴展(註入spring上下文前後),而InstantiationAwareBeanPostProcessor
介面在此基礎上增加了3個方法,把可擴展的範圍增加了實例化階段和屬性註入階段。
該類主要的擴展點有以下6個方法,其中有兩個是BeanPostProcessor的擴展,主要在bean生命周期的兩大階段:實例化階段和初始化階段,下麵一起進行說明,按調用順序為:
postProcessBeforeInstantiation
:在Bean實例化之前調用,如果返回null,一切按照正常順序執行;如果返回的是一個實例的對象,那麼postProcessAfterInstantiation()
會執行,其他的擴展點將不再觸發。postProcessAfterInstantiation
:在Bean實例化之後調用,可以對已實例化的Bean進行進一步的自定義處理。postProcessPropertyValues
(方法在spring5.1版本後就已棄用):bean已經實例化完成,在屬性註入時階段觸發,@Autowired
,@Resource
等註解原理基於此方法實現;可以修改Bean的屬性值或進行其他自定義操作,當postProcessAfterInstantiation返回true才執行。postProcessBeforeInitialization
(BeanPostProcessor的擴展):初始化bean之前,相當於把bean註入spring上下文之前;可用於創建代理類,如果返回的不是 null(也就是返回的是一個代理類) ,那麼後續只會調用 postProcessAfterInitialization() 方法postProcessAfterInitialization
(BeanPostProcessor的擴展):初始化bean之後,相當於把bean註入spring上下文之後;返回值會影響 postProcessProperties() 是否執行,其中返回 false 的話,是不會執行。postProcessProperties()
:在 Bean 設置屬性前調用;用於修改 bean 的屬性,如果返回值不為空,那麼會更改指定欄位的值
註意:InstantiationAwareBeanPostProcessor和 BeanPostProcessor 是可以同時被實現的,並且也會同時生效,但是InstantiationAwareBeanPostProcessor的執行時機要稍早於BeanPostProcessor;具體看上面調用順序圖
InstantiationAwareBeanPostProcessor
提供了更細粒度的控制,可以在 Bean 的實例化和屬性設置過程中插入自定義邏輯。無論是替換預設的實例化過程、控制依賴註入,還是修改屬性值,InstantiationAwareBeanPostProcessor
都提供了強大的靈活性和可擴展性,使得開發者可以在 Bean 的生命周期中進行更精細的控制。
使用場景
- 在實例化之前替換 Bean:替換預設的 Bean 實例化過程,可能是返回一個代理對象。
@Component
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("實例化之前替換 Bean: " + beanName);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("調用方法: " + method.getName());
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之後的 Bean: " + beanName);
return bean;
}
}
- 控制實例化後的依賴註入過程:在實例化後但在依賴註入之前進行一些自定義邏輯。
@Component
public class DependencyInjectionControlPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("實例化之後控制依賴註入: " + beanName);
return false; // 不進行預設的依賴註入
}
return true;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之後的 Bean: " + beanName);
return bean;
}
}
- 修改屬性值:在屬性值設置過程中進行干預,修改或添加屬性值。
@Component
public class PropertyModificationPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("設置屬性值之前: " + beanName);
// 修改屬性值的邏輯
}
return pvs;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之後的 Bean: " + beanName);
return bean;
}
}
SmartInstantiationAwareBeanPostProcessor
org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor
介紹
SmartInstantiationAwareBeanPostProcessor
與其他擴展點最明顯的不同,就是在實際的業務開發場景中應用到的機會並不多,主要是在Spring內部應用。
該擴展介面有3個觸發點方法:
predictBeanType
:該觸發點發生在postProcessBeforeInstantiation
之前(也就是在 InstantiationAwareBeanPostProcessor的方法之前,在圖上並沒有標明,因為一般不太需要擴展這個點),這個方法用於預測Bean的類型,返回第一個預測成功的Class類型,如果不能預測,則返回null;當調用BeanFactory.getType(name)
時當通過bean的名字無法得到bean類型信息時就調用該回調方法來決定類型信息。determineCandidateConstructors
:該觸發點發生在postProcessBeforeInstantiation
之後,用於決定使用哪個構造器構造Bean,返回的是該bean的所有構造函數列表;如果不指定,預設為null,即bean的無參構造方法。用戶可以擴展這個點,來自定義選擇相應的構造器來實例化這個bean。getEarlyBeanReference
:該觸發點發生在postProcessAfterInstantiation
之後,主要用於Spring迴圈依賴問題的解決,如果Spring中檢測不到迴圈依賴,這個方法不會被調用;當存在Spring迴圈依賴這種情況時,當bean實例化好之後,為了防止有迴圈依賴,會提前暴露回調方法,用於bean實例化的後置處理,會在InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法觸發執行之後執行;
註意:同InstantiationAwareBeanPostProcessor,由於SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor的子類,因此也SmartInstantiationAwareBeanPostProcessor 也同樣能擴展 InstantiationAwareBeanPostProcessor的所有方法。但是如果有兩個類分別重寫了 SmartInstantiationAwareBeanPostProcessor 和 InstantiationAwareBeanPostProcessor 的方法,那麼重寫 InstantiationAwareBeanPostProcessor 的類的方法 會先於 重寫了 SmartInstantiationAwareBeanPostProcessor的類的方法(註意,這裡說的是兩者都有的方法)。
使用場景
- 自定義構造函數選擇:在實例化 Bean 時,選擇特定的構造函數。
@Component
public class CustomConstructorSelectionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("選擇自定義構造函數: " + beanName);
try {
return new Constructor<?>[] { beanClass.getConstructor(String.class) };
} catch (NoSuchMethodException e) {
throw new BeansException("找不到指定的構造函數", e) {};
}
}
return null;
}
}
public class MyBean {
private String name;
public MyBean() {
this.name = "Default Name";
}
public MyBean(String name) {
this.name = name;
}
@Override
public String toString() {
return "MyBean{name='" + name + "'}";
}
}
- 解決迴圈依賴問題:通過提供早期 Bean 引用,解決迴圈依賴問題。
@Component
public class EarlyBeanReferencePostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
System.out.println("獲取早期 Bean 引用: " + beanName);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("調用方法: " + method.getName());
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
return bean;
}
}
- 預測 Bean 類型:在 Bean 實例化之前,預測 Bean 的類型。
@Component
public class BeanTypePredictionPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == MyBean.class) {
System.out.println("預測 Bean 類型: " + beanName);
return MyBean.class;
}
return null;
}
}
MergedBeanDefinitionPostProcessor
org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor
介紹
MergedBeanDefinitionPostProcessor 繼承自 BeanPostProcessor。調用的時機是,在實例化之後進行的調用,只要是收集bean上的屬性的,比如收集標記了某些註解的欄位或者方法,都可以基於MergedBeanDefinitionPostProcessor來進行擴展。
對於不同方式導入的Bean定義,如果存在重覆對同一個Bean的定義,則會根據allowBeanDefinitionOverriding屬性是否設置為true,判斷是否允許Bean定義的覆蓋,如果不允許,則拋出異常。而在Bean實例化之前,會進行BeanDefinition類型的歸一化,即 mergeBeanFintion ,統一轉換為RootBeanfintion進行後續處理。當然,這裡的merge更多指代的是父子Bean定義的合併。
也用於收集bean上的註解,比如常見的@Value、@NacosValue、@Mapper等,再將收集好的數據緩存在injectionMetadataCache中,以便後續比如屬性註入的時候使用。
該介面有兩個擴展方法:
postProcessMergedBeanDefinition
:此方法在Spring將多個Bean定義合併為一個RootBeanDefinition
之後,但在實例化Bean之前被調用。主要作用是讓開發者有機會在Bean定義合併後,對其進行進一步的定製和調整。使用場景如下:- 自定義註解處理:處理自定義註解並將其應用於Bean定義。
- 屬性修改:在Bean實例化之前對Bean定義中的某些屬性進行調整或設置預設值。
resetBeanDefinition
:此方法在Bean定義被重置時調用。它通常用於清理或重置與特定Bean定義相關的狀態或緩存。使用場景如下:- 狀態清理:清理緩存或臨時狀態,以便Bean定義可以被重新解析。
- 重置自定義元數據:在Bean定義被重置時,重置自定義的元數據或狀態。
使用場景
- 對合併後的 Bean 定義信息進行修改:在 Bean 實例化之前,修改其定義信息,例如添加屬性值或修改構造函數參數。
@Component
public class CustomMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor, BeanPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType == MyBean.class) {
System.out.println("合併後的 Bean 定義信息, Bean 名稱: " + beanName);
// 修改合併後的 Bean 定義信息
beanDefinition.getPropertyValues().add("name", "修改後的名稱");
}
}
@Override
public void resetBeanDefinition(String beanName) {
System.out.println("重置 Bean 定義信息, Bean 名稱: " + beanName);
// 實現重置邏輯
}
}
public class MyBean {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MyBean{name='" + name + "'}";
}
}
- 實現通用的自定義邏輯:在所有 Bean 實例化之前,執行一些通用的自定義邏輯。
@Component
public class CommonLogicMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor, BeanPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
System.out.println("處理合併後的 Bean 定義信息, Bean 名稱: " + beanName);
// 添加通用的自定義邏輯,例如給所有 Bean 添加某個屬性
beanDefinition.getPropertyValues().add("commonProperty", "通用屬性值");
}
@Override
public void resetBeanDefinition(String beanName) {
System.out.println("重置 Bean 定義信息, Bean 名稱: " + beanName);
// 實現重置邏輯
}
}
public class MyBean {
private String name;
private String commonProperty;
public void setName(String name) {
this.name = name;
}
public void setCommonProperty(String commonProperty) {
this.commonProperty = commonProperty;
}
@Override
public String toString() {
return "MyBean{name='" + name + "', commonProperty='" + commonProperty + "'}";
}
}
- 條件性地重置 Bean 定義信息:在某些條件下重置 Bean 的定義信息,使得下一次的實例化可以使用更新後的定義信息。
@Component
public class ConditionalResetMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor, BeanPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
System.out.println("處理合併後的 Bean 定義信息, Bean 名稱: " + beanName);
// 這裡可以根據條件決定是否修改 Bean 定義
if (beanName.equals("conditionalBean")) {
beanDefinition.getPropertyValues().add("name", "重置後的名稱");
}
}
@Override
public void resetBeanDefinition(String beanName) {
System.out.println("重置 Bean 定義信息, Bean 名稱: " + beanName);
// 這裡可以實現條件性重置邏輯
}
}
public class ConditionalBean {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ConditionalBean{name='" + name + "'}";
}
}
BeanNameAware
org.springframework.beans.factory.BeanNameAware
介紹
這個類是Aware擴展的一種,觸發點在bean的初始化之前,也就是postProcessBeforeInitialization
之前,這個類的觸發點方法只有一個:setBeanName
。
用於讓 Bean 獲得其在 Spring 容器中的名稱。實現了 BeanNameAware
介面的 Bean 可以在初始化時獲得自身的 Bean 名稱,這在某些需要根據 Bean 名稱進行邏輯處理的場景非常有用。
使用場景
- 記錄或日誌輸出 Bean 名稱:在某些應用場景中,開發者可能希望在 Bean 初始化時記錄或輸出 Bean 的名稱。這對調試和日誌記錄非常有幫助。
@Component
public class LoggingBean implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("設置 Bean 名稱: " + name);
}
public void doSomething() {
System.out.println("正在執行某些操作, 當前 Bean 名稱: " + beanName);
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
LoggingBean loggingBean = context.getBean(LoggingBean.class);
loggingBean.doSomething();
}
}
- 根據 Bean 名稱實現條件性邏輯:有時,一個 Bean 可能需要根據其名稱決定執行不同的邏輯。例如,可以在初始化過程或某些方法調用中根據 Bean 名稱執行特定操作。
@Component
public class ConditionalLogicBean implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("設置 Bean 名稱: " + name);
}
public void performAction() {
if ("conditionalLogicBean".equals(beanName)) {
System.out.println("執行特定邏輯, 因為這是 conditionalLogicBean");
} else {
System.out.println("執行普通邏輯");
}
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ConditionalLogicBean conditionalLogicBean = context.getBean(ConditionalLogicBean.class);
conditionalLogicBean.performAction();
}
}
- 動態註冊多個同類型的 Bean:在某些複雜的應用場景中,可能需要動態註冊多個同類型的 Bean,並且需要根據名稱區分它們。實現
BeanNameAware
介面可以很方便地獲取和使用這些 Bean 的名稱。
@Component("beanA")
public class DynamicBeanA implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("設置 Bean 名稱: " + name);
}
public void execute() {
System.out.println("執行 Bean: " + beanName);
}
}
@Component("beanB")
public class DynamicBeanB implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("設置 Bean 名稱: " + name);
}
public void execute() {
System.out.println("執行 Bean: " + beanName);
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DynamicBeanA beanA = (DynamicBeanA) context.getBean("beanA");
DynamicBeanB beanB = (DynamicBeanB) context.getBean("beanB");
beanA.execute();
beanB.execute();
}
}
BeanClassLoaderAware
org.springframework.beans.factory.BeanClassLoaderAware
介紹
用於讓一個 Bean 獲取到載入它的 ClassLoader
。實現這個介面的 Bean 會在其屬性設置完成後、初始化方法調用之前被註入 ClassLoader
。該介面定義了一個方法:
void setBeanClassLoader(ClassLoader classLoader)
:在某些需要動態載入類的場景中,獲取ClassLoader
是非常有用的。
使用場景
- 動態載入類:有時候,我們可能需要在運行時動態載入類,利用
BeanClassLoaderAware
可以方便地獲取到ClassLoader
來實現這一需求。
@Component
public class DynamicClassLoader implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已設置類載入器");
}
public void loadClass(String className) {
try {
Class<?> clazz = classLoader.loadClass(className);
System.out.println("已載入類:" + clazz.getName());
} catch (ClassNotFoundException e) {
System.out.println("類未找到:" + className);
}
}
}
@SpringBootApplication
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
DynamicClassLoader dynamicClassLoader = context.getBean(DynamicClassLoader.class);
dynamicClassLoader.loadClass("java.util.ArrayList");
dynamicClassLoader.loadClass("不存在的類");
}
}
- 檢查類的可用性:在某些情況下,我們可能需要檢查某個類是否在當前的類路徑中可用。利用
BeanClassLoaderAware
可以方便地實現這一需求。
@Component
public class ClassAvailabilityChecker implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已設置類載入器");
}
public boolean isClassAvailable(String className) {
try {
Class<?> clazz = classLoader.loadClass(className);
System.out.println("類可用:" + clazz.getName());
return true;
} catch (ClassNotFoundException e) {
System.out.println("類不可用:" + className);
return false;
}
}
}
@SpringBootApplication
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
ClassAvailabilityChecker checker = context.getBean(ClassAvailabilityChecker.class);
checker.isClassAvailable("java.util.HashMap");
checker.isClassAvailable("不存在的類");
}
}
- 載入資源文件:通過
BeanClassLoaderAware
獲取的ClassLoader
,我們還可以方便地載入資源文件。
@Component
public class ResourceLoader implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("已設置類載入器");
}
public void loadResource(String resourcePath) {
InputStream inputStream = classLoader.getResourceAsStream(resourcePath);
if (inputStream != null) {
System.out.println("資源已載入:" + resourcePath);
} else {
System.out.println("資源未找到:" + resourcePath);
}
}
}
@SpringBootApplication
public class AppConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class, args);
ResourceLoader resourceLoader = context.getBean(ResourceLoader.class);
resourceLoader.loadResource("application.properties");
resourceLoader.loadResource("不存在的資源");
}
}
BeanFactoryAware
org.springframework.beans.factory.BeanFactoryAware
介紹
這個類只有一個觸發點,發生在bean的實例化之後,註入屬性之前,也就是Setter之前。這個類的擴展點方法為setBeanFactory
,可以拿到BeanFactory
這個屬性,從而能夠進行更複雜的 Bean 操作。例如,動態獲取其他 Bean、檢查 Bean 的狀態等。
使用場景
- 動態獲取其他 Bean:通過實現
BeanFactoryAware
介面,一個 Bean 可以在運行時動態獲取其他 Bean。這在一些需要解耦的場景下非常有用。
@Component
public class DynamicBeanFetcher implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("註入 BeanFactory 實例");
}
public void fetchAndUseBean() {
MyBean myBean = beanFactory.getBean(MyBean.class);
System.out.println("獲取到的 Bean 實例: " + myBean);
}
}
@Component
public class MyBean {
@Override
public String toString() {
return "這是 MyBean 實例";
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DynamicBeanFetcher fetcher = context.getBean(DynamicBeanFetcher.class);
fetcher.fetchAndUseBean();
}
}
- 檢查 Bean 的狀態:通過
BeanFactoryAware
,可以在運行時檢查某個 Bean 是否存在或者其狀態,這對一些需要動態檢查 Bean 狀態的場景非常有用。
@Component
public class BeanStateChecker implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("註入 BeanFactory 實例");
}
public void checkBeanState() {
boolean exists = beanFactory.containsBean("myBean");
System.out.println("MyBean 是否存在: " + exists);
}
}
@Component("myBean")
public class MyBean {
@Override
public String toString() {
return "這是 MyBean 實例";
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
BeanStateChecker checker = context.getBean(BeanStateChecker.class);
checker.checkBeanState();
}
}
- 創建複雜 Bean 的初始化邏輯:在一些複雜的業務場景中,有時需要在 Bean 初始化時執行一些複雜的邏輯,例如動態創建其他 Bean 並註入到當前 Bean 中。通過
BeanFactoryAware
可以實現這一點。
@Component
public class ComplexBeanInitializer implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("註入 BeanFactory 實例");
}
public void initializeComplexBean() {
MyBean myBean = beanFactory.getBean(MyBean.class);
System.out.println("初始化複雜 Bean, 獲取到的 MyBean 實例: " + myBean);
// 在這裡可以執行複雜的初始化邏輯
}
}
@Component
public class MyBean {
@Override
public String toString() {
return "這是 MyBean 實例";
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ComplexBeanInitializer initializer = context.getBean(ComplexBeanInitializer.class);
initializer.initializeComplexBean();
}
}
ApplicationContextAwareProcessor
org.springframework.context.support.ApplicationContextAwareProcessor
介紹
該類本身並沒有擴展點,而是 BeanPostProcessor 擴展介面的具體實現,但是該類內部卻有6個擴展點可供實現 ,這些擴展點的觸發時機在bean實例化之後,初始化之前。
可以看到,該類用於執行各種驅動介面,在bean實例化之後,屬性填充之後。其內部有6個擴展點可供實現,這幾個介面都是Spring預留的重點擴展實現,與Spring的 Bean的生命周期 密切相關,以下按照擴展點調用順序介紹:
-
EnvironmentAware
:用於獲取EnviromentAware
的一個擴展類,這個變數非常有用, 可以獲得系統內的所有參數;另外也可以通過註入的方式來獲得Environment,用哪種方式需要以實現場景而決定。當然個人認為這個Aware沒必要去擴展,因為spring內部都可以通過註入的方式來直接獲得。 -
EmbeddedValueResolverAware
:用於獲取StringValueResolver
的一個擴展類,StringValueResolver
可以獲取基於String類型的properties的變數;但一般我們都用@Value
的方式來獲取properties的變數,用哪種方式需要以實現場景而決定。如果實現了這個Aware介面,把StringValueResolver
緩存起來,通過這個類去獲取String
類型的變數,效果是一樣的。 -
ResourceLoaderAware
:用於獲取ResourceLoader
的一個擴展類,ResourceLoader
可以用於獲取classpath內所有的資源對象。 -
ApplicationEventPublisherAware
:用於獲取ApplicationEventPublisher
的一個擴展類,ApplicationEventPublisher
可以用來發佈事件;這個對象也可以通過spring註入的方式來獲得,結合ApplicationListener
來共同使用,下文在介紹ApplicationListener
時會詳細提到。 -
MessageSourceAware
:用於獲取MessageSource
的一個擴展類,MessageSource
主要用來做國際化。 -
ApplicationContextAware
:用來獲取ApplicationContext
的一個擴展類,ApplicationContext
就是spring上下文管理器,可以手動的獲取任何在spring上下文註冊的bean。較多的做法是擴展這個介面來緩存spring上下文,包裝成靜態方法。
同時ApplicationContext
也實現了BeanFactory
,MessageSource
,ApplicationEventPublisher
等介面,也可以用來做相關介面的事情。
使用場景
- 動態獲取其他 Bean:通過實現
ApplicationContextAware
介面,Bean 可以在運行時動態獲取其他 Bean,這在一些需要解耦的場景下非常有用。
@Component
public class DynamicBeanFetcher implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("註入 ApplicationContext 實例");
}
public void fetchAndUseBean() {
MyBean myBean = applicationContext.getBean(MyBean.class);
System.out.println("獲取到的 Bean 實例: " + myBean);
}
}
@Component
public class MyBean {
@Override
public String toString() {
return "這是 MyBean 實例";
}
}
@Configuration
@ComponentScan(basePackages = "com.seven")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DynamicBeanFetcher fetcher = context.getBean(DynamicBeanFetcher.class);
fetcher.fetchAndUseBean();
}
}
- 使用 ApplicationContext 進行事件發佈:在一些場景中,Bean 可能需要發佈事件。通過實現
ApplicationContextAware
介面,可以方便地獲取ApplicationContext
實例併發布事件。
@Component
public class EventPublisherBean implements ApplicationContextAware, ApplicationEventPublisherAware {
private ApplicationContext applicationContext;
private ApplicationEventPublisher eventPublisher;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("註入 ApplicationContext 實例");
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void publishCustomEvent(String message) {
CustomEvent customEvent = new CustomEvent(this, message);
event