Spring應用 4 ApplicationContextAware應用理解
Aware接口的Bean在被初始之後,可以取得一些相對應的資源。
Aware接口本身並不具備什麼功能,一般是用於子類繼承後,Spring上下文初始化bean的時候會對這個bean傳入需要的資源。
例如ApplicationContextAware接口,可以在Spring初始化實例 Bean的時候,可以通過這個接口將當前的Spring上下文傳入。
注意:一定要讓繼承ApplicationContextAware接口的bean被Spring上下文管理,在application.xml文件中定義對應的bean標籤,或者使用@Component標註。
ApplicationContextAware的使用
1.實現ApplicationContextAware接口,創建一個類實現 這個接口ApplicationContextAware, 在該類中定義ApplicationContext靜態變量 。並對setApplicationContext方法進行重寫。
通過在實現ApplicationContextAware在組件bean初始化的時候傳入ApplicationContext,這樣可以根據ApplicationContext中的一些數據進行一些自定義的操作
@Component
public class ControllerTest implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private static ClassPathXmlApplicationContext XapplicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.XapplicationContext = (ClassPathXmlApplicationContext) applicationContext;
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(RpcService.class);
applicationContext.getBean("userService");
}
}
通過創建一個實例,用於存儲當前初始化的Spring上下文,可以在後續的應用場景中調用。
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHelper.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> clazz){
return applicationContext.getBean(clazz);
}
}
2.初始化Spring上下文
new ClassPathXmlApplicationContext("server-spring.xml");
主要有以下接口定義
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
ApplicationContextAware的應用
ApplicationContextAware的最本質的應用就是:對當前bean傳入對應的Spring上下文。
1.保存Spring上下文
例如上文中的ApplicationContextHelper,專門創建一個Bean,用於維護Spring ApplicationContext。並且可以將ApplicationContextHelper通過@Resource的形式注入到其他組件中。這樣相當於爲所有的Bean提供可一個操作Spring上下文的工具類
2.監聽上下文啓動,並完成相關操作
通過在實例化到時候,通過上下文調用setApplicationContext方法,然後完成一些自定義的操作。例如加載某些特殊的實例,對bean進行操作等。
ApplicationContextAware源碼
在AbstractApplicationContext的refresh方法中的prepareBeanFactory(beanFactory);方法。添加了ApplicationContextAwareProcessor處理器,
ApplicationContextAwareProcessor是繼承了BeanPostProcessor接口。在bean實例化的時候,也就是Spring激活bean的init-method方法的前後,會調用BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization。
在ApplicationContextAwareProcessor我們同樣關心這兩個方法。在postProcessBeforeInitialization方法中,可以看到會調用invokeAwareInterfaces方法,其中判斷了當前初始化bean時候繼承了對應的Aware,如果是則調用對應的set方法,傳入對應的資源。
所有的BeanPostProcessor都將在AbstractAutowireCapableBeanFactory類的initializeBean方法中,通過調用applyBeanPostProcessorsBeforeInitialization方法完成所有實現BeanPostProcessor接口的postProcessBeforeInitialization的調用。
AbstractApplicationContext.prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
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(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.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);
.....
...
..
}
ApplicationContextAwareProcessor.postProcessBeforeInitialization
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
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(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}else {
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(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
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;
}
其他Web擴展
在web應用中,還可以添加ServletContextAware,ServletConfigAware。
在web項目中,Spring容器的加載是通常是通過XmlWebApplicationContext進行的。
它的父類AbstractRefreshableWebApplicationContext,在postProcessBeanFactory方法中進行了如下操作(postProcessBeanFactory方法被AbstractApplicationContext的refresh方法調用)
AbstractRefreshableWebApplicationContext.postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
ServletContextAwareProcessor.postProcessBeforeInitialization
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}