1、spring容器中的aware接口介紹java
Spring中提供了各類Aware接口,比較常見的如BeanFactoryAware,BeanNameAware,ApplicationContextAware,BeanClassLoaderAware等,方便從上下文中獲取當前的運行環境。咱們先從使用的角度來講明aware接口的使用方式,舉例如咱們想獲得當前的BeanFactory,咱們可讓咱們的實現類繼承BeanFactoryAware接口,而後經過接口注入的方式獲得當前容器中的BeanFactory:web
public class Fruit implements BeanFactoryAware { private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } }
咱們的Fruit類實現了aware接口,若是咱們直接在應用中new一個Fruit的對象,固然是拿不到beanFactory變量的,咱們必須在spring的配置文件中聲明咱們的fruit對象才行,也就是說fruit對象必須交給容器進行管理,容器幫你把各類aware接口中想要注入的對象設置到bean中。具體看容器管理aware接口的代碼實現,代碼在AbstractAutowireCapableBeanFactory的initializeBean方法中:spring
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) { // 判斷對象實現的接口類型,處理特定的三種接口類型:BeanNameAware、BeanClassLoaderAware和BeanFactoryAware。 if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(this); } // 開始Bean初始化前處理、初始化、初始化後處理 Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
能夠看出來,aware接口的各類處理是在屬性設置完成以後、bean初始化以前完成的。顯然的,若是咱們直接new出來一個bean,這些框架性的特性是沒有使用到的。除了BeanFactoryAware、BeanNameAware、BeanClassLoaderAware以外的那些aware接口,好比ApplicationContextAware,再好比Webx中的自定義aware接口,它們又是怎麼作到接口注入的呢?原來在應用中建立上下文容器時會註冊一個BeanPostProcessor------ApplicationContextAwareProcessor,在這個類裏面進行了context的注入,這樣咱們就能可以拿到bean中的context對象:app
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 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); } return bean; }
那麼容器是在何時把ApplicationContextAwareProcessor的對象註冊到context的BeanPostProcessor列表中的呢,奧祕在org.springframework.context.support.AbstractApplicationContext.prepareBeanFactory(ConfigurableListableBeanFactory)方法中:框架
// Tell the internal bean factory to use the context's class loader. beanFactory.setBeanClassLoader(getClassLoader()); // Populate the bean factory with context-specific resource editors. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //在這裏註冊了咱們想要的BeanPostProcessor beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
2、瞭解webx中實現的aware接口ide
咱們瞭解了aware的實現原理,咱們就能夠本身來實現本身的aware接口了。Webx就是這麼作的(webx自己做爲一個容器,自己註冊了各種aware接口的BeanPostProcessor),好比咱們想要感知到當前環境是不是生產模式,咱們只須要實現ProductionModeAware接口就可以得到生產模式的值了。咱們使用aware接口感受很神奇很簡便,緣由是不少工做框架已經幫咱們作了。webx中使用ProductionModeAwarePostProcessor這個BeanPostProcessor來進行生產模式的注入。在postProcessBeforeInitialization方法中:post
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof ProductionModeAware) { ((ProductionModeAware) bean).setProductionMode(configuration.isProductionMode()); } return bean; }
因此任何實現了ProductionModeAware接口的類,在webx容器中都可以得到生產模式的取值。測試
3、自定義aware接口實現ui
瞭解了箇中原理,那麼自定義aware接口實現起來並不複雜。咱們只須要2步操做:1.實現咱們aware接口的postprocessor,並在容器中註冊;2.bean實體類集成咱們自定義的aware接口並實現。代碼以下:Aware接口比較簡單,就作一件事情,把Apple對象注入。this
public interface AppleAware { void setApple(Apple a); }
咱們的BeanPostProcessor會檢查是不是AppleAware接口,由於註冊到容器的BeanPostProcessor會對每個bean都作一次掃描:
public class AppleAwarePostProcessor implements BeanPostProcessor { private Apple a; public AppleAwarePostProcessor(Apple a) { this.a = a; } /* (non-Javadoc) * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof AppleAware) { ((AppleAware) bean).setApple(a); } return bean; } /* (non-Javadoc) * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub return bean; } }
實體類Market實現了AppleAware接口,可以獲得Apple對象的注入:
public class Market implements AppleAware { private Apple a; @Override public void setApple(Apple a) { this.a = a; } public String getName() { return a.getName(); } }
最後是咱們的測試類,必定要把咱們的BeanPostProcessor加入到當前容器中,這一點很是重要:
public class TestAware { public static void main(String args[]) { ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); BeanPostProcessor bpp = new AppleAwarePostProcessor((Apple)beanFactory.getBean("apple")); // 工廠對象中加入咱們自定義的BeanPostProcessor beanFactory.addBeanPostProcessor(bpp); Market market = (Market) beanFactory.getBean("market"); System.out.println(market.getName()); } }
4、