理解Spring Boot的ApplicationContextAwareProcessor:擴展點背后的魔法
前言
這篇文章主要來分享Springboot的擴展點之ApplicationContextAwareProcessor,而ApplicationContextAwareProcessor本身并不是擴展點,而是BeanPostProcessor擴展接口的具體實現(xiàn),關(guān)于BeanPostProcessor擴展接口的功能特性、實現(xiàn)方式和工作原理可以移步Springboot擴展點之BeanPostProcessor,但是還是要當作Springboot的擴展點來分析,是因為其內(nèi)部有6個擴展點可供實現(xiàn),分別是EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware,這幾個接口都是Spring預留的重點擴展實現(xiàn),與Spring的Bean的生命周期密切相關(guān)。
功能特性
ApplicationContextAwareProcessor本身并不是擴展點,而是實現(xiàn)了BeanPostProcessor,并實現(xiàn)postProcessBeforeInitialization(),所以并不需要去實現(xiàn)它,但是其內(nèi)部包含了以下6個接口實現(xiàn)的執(zhí)行時機,這幾個接口的功能作用分別是:
1、EnvironmentAware:用于獲取Enviroment,Enviroment可以獲得系統(tǒng)內(nèi)的所有參數(shù);另外也可以通過注入的方式來獲得Environment,用哪種方式需要以實現(xiàn)場景而決定。
2、EmbeddedValueResolverAware:用于獲取StringValueResolver,StringValueResolver可以獲取基于String類型的properties的變量;另外還可以使用@Value的方式來獲取properties的變量,用哪種方式需要以實現(xiàn)場景而決定。
3、ResourceLoaderAware:用于獲取ResourceLoader,ResourceLoader可以用于獲取classpath內(nèi)所有的資源對象。
4、ApplicationEventPublisherAware:用于獲取ApplicationEventPublisher,ApplicationEventPublisher可以用來發(fā)布事件,當然這個對象也可以通過spring注入的方式來獲得,具體的實現(xiàn)方式可以參考Springboot事件監(jiān)聽機制的實戰(zhàn)應用。
5、MessageSourceAware:用于獲取MessageSource,MessageSource主要用來做國際化。
6、ApplicationContextAware:用來獲取ApplicationContext,ApplicationContext就是Spring上下文管理器。
下面定義一個Bird類,實現(xiàn)ApplicationContextAware接口,以Bird為例分享ApplicationContextAwareProcessor的功能特性。
@Component
@Slf4j
public class Bird implements ApplicationContextAware {
private String name="xiao niao";
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
log.info("----Spring的上下文環(huán)境application被注入");
}
}
@Test
public void test3(){
log.info("----單元測試執(zhí)行開始");
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
log.info("----單元測試執(zhí)行完畢");
}
單元測執(zhí)行結(jié)果
圖片
工作原理
注冊時機
ApplicationContextAwareProcessor的注冊時機,即準備BeanFactory的時候,注冊的入口在AbstractApplicationContext#refresh----->AbstractApplicationContext#prepareBeanFactory方法中。
圖片
執(zhí)行邏輯
ApplicationContextAwareProcessor#postProcessBeforeInitialization的擴展邏輯很簡單:即當前Bean是否實現(xiàn)了EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware,如果不是,則直拉返回,如果是,則執(zhí)行XxxAware接口的擴展邏輯;
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//如果非實現(xiàn)EnvironmentAware、EmbeddedValueResolverAware、
//ResourceLoaderAware、ApplicationEventPublisherAware、
//MessageSourceAware、ApplicationContextAware,則直拉返回;
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
//如果實現(xiàn)XXXAware接口,則執(zhí)行相關(guān)Aware接口的擴展方法;
invokeAwareInterfaces(bean);
}
return bean;
}
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);
}
}
}
執(zhí)行時機
因為ApplicationContextAwareProcessor實現(xiàn)了BeanPostProcessor接口,并重寫了postProcessBeforeInitialization()。關(guān)于BeanPostProcessor接口的執(zhí)行時機可移步Springboot擴展點之BeanPostProcessor,這里就不再反復贅述了。
圖片
總結(jié)
通過以上的分析,可以了解到:
1、ApplicationContextAwareProcessor實現(xiàn)BeanPostProcessor接口,是Spring擴展點之BeanPostProcessor的內(nèi)部經(jīng)典實現(xiàn)。
2、ApplicationContextAwareProcessor#postProcessBeforeInitialization內(nèi)部邏輯很簡單,主要是執(zhí)行了XxxAware相關(guān)擴展接口具體實現(xiàn);
3、ApplicationContextAwareProcessor注冊時機相對比較早,即BeanFactory實例化后,相關(guān)屬性初始化時;
4、ApplicationContextAwareProcessor#postProcessBeforeInitialization的執(zhí)行時機,是在Spring管理的Bean實例化、屬性注入完成后,InitializingBean#afterPropertiesSet方法以及自定義的初始化方法之前;