談談Spring的ApplicationContextAware介面
談談Spring的ApplicationContextAware介面
現象:
我們寫一個類,實現ApplicationContextAware介面,類上再加一個@Component後,執行專案,你會發現在我們實現的setApplicationContext會傳進來Spring的ApplicationContext。
@Component public class TestMyBeanPostProcess implements ApplicationContextAware { @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { /* 此處將會傳進來ApplicationContext */ } }
為什麼?
對於應用方面,我們只需要知道實現此介面再@Component即可,但我相信你還是比較喜歡知道Spring具體怎麼做的。
原始碼檢視
首先:
// 建立AnnotationConfigApplicationContext,傳入AppConfig.class配置類
new AnnotationConfigApplicationContext(AppConfig.class);
// AppConfig.class中程式碼如下:
@Configuration
@ComponentScan("com.dh")
public class AppConfig {
}
進入到AnnotationConfigApplicationContext的建構函式中:
/** * Create a new AnnotationConfigApplicationContext, deriving bean definitions * from the given annotated classes and automatically refreshing the context. * @param annotatedClasses one or more annotated classes, * e.g. {@link Configuration @Configuration} classes */ public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); } // 這裡面第一行程式碼this(): public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } // 這裡乾的事情我們忽略不計,就是設定一個reader和scanner,分別對應這兩個類:AnnotatedBeanDefinitionReader reader;ClassPathBeanDefinitionScanner scanner;這兩個類做的什麼事情也不要去多想,這不是這次的重點(涉及到Spring的Bean資訊掃描和讀取)。 // 再看下一行register(annotatedClasses); // 這裡面實際上做的事情就是將我們傳入的AppConfig.class解析資訊,包括帶的註解等其他資訊,然後封裝到BeanDefinition中然後存入到beanNameList和BeanDefinitionList中。
重要的第三行“refresh()”呼叫的方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.,準備提前工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.,獲取BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.本次的重點程式碼
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
prepareBeanFactory()為重點的程式碼:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// 設定classLoader以及其他一些物件
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
//
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
// 注意看這一行:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)):
從這一行程式碼很簡單,但不簡單的是ApplicationContextAwareProcessor和BeanPostProcessor。
BeanPostProcessor:
是一個可以讓我們干預Bean例項化的介面,當我們實現此介面並重寫裡面的postProcessBeforeInitialization、postProcessAfterInitialization方法的後,每個Bean例項化完成後都會呼叫這兩個方法,那麼當有多個類實現了BeanPostProcessor的時候,如果想指定BeanPostProcessor被呼叫的順序的話,需要實現此介面:PriorityOrdered,此介面的返回值越小執行的順序越靠前。BeanPostProcessor此擴充套件介面可以使我們干預Bean的例項化過程,例如實現AOP等功能,例如我們注入一個A類,裡面有一個a方法,然後我們實現BeanPostProcessor介面的類當中postProcessBeforeInitialization方法裡面會傳入這個例項化後的A類,我們在這方法裡面使用任意動態代理方法來對其進行代理,再將代理後得到的類return回去,此時Spring容器中的A類就是我們返回的已經代理過後的類,這樣就實現了AOP的操作,當然其他的大部分功能都可以使用BeanPostProcessor來進行實現,Spring預設提供了50個以上的BeanPostProcessor,其中包含引數校驗、aop的功能。總結一下:BeanPostProcessor是Spring給我們提供的擴充套件介面,此擴充套件介面可以讓我們干預Bean的例項化過程已達到某些功能,當然擴充套件點肯定不止BeanPostProcessor一個,還有大約4個左右,例如BeanFactoryPostProcessor等。
ApplicationContextAwareProcessor:
/**
* 此PostProcessor中包含很多回調方法,例如拿到Application,拿到Environment,然後通過介面的方法設定回去
*/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
/* 在這裡判斷當前的bean是否實現我們需要操作的介面,如果有的話,那麼設定acc */
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
/* 如果acc不為空,則去挨個判斷實現的介面,然後去其進行回撥 */
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
進入到這個類裡面來以後會發現,它實現了BeanPostProcessor介面,並重寫了我們上面提到的兩個方法:postProcessBeforeInitialization,postProcessAfterInitialization。重點看postProcessBeforeInitialization,在這裡面先是一堆判斷,這些判斷我們不關心,看invokeAwareInterfaces(bean),這一行方法呼叫。
在這個方法裡面判斷當前類是否實現了EnvironmentAware介面,如果實現了則強轉後將Environmentset過去,後續if中都是相同的道理,只是介面不同,此時我們就能發現最後裡面就是我們文章標題裡面寫的ApplicationContextAware介面,那麼看到這裡你是不是有點明白了。對,就是你想的那樣。