Spring應用 4 ApplicationContextAware應用理解

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章