spring源碼:Aware接口


一、spring容器中的aware接口介紹

  Spring中提供了各種Aware接口,比較常見的如BeanFactoryAware,BeanNameAware,ApplicationContextAware,BeanClassLoaderAware等,方便從上下文中獲取當前的運行環境。我們先從使用的角度來說明aware接口的使用方式,舉例如我們想得到當前的BeanFactory,我們可以讓我們的實現類繼承BeanFactoryAware接口,然后通過接口注入的方式得到當前容器中的BeanFactory:

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方法中:

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對象:

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);

二、了解webx中實現的aware接口

  我們了解了aware的實現原理,我們就可以自己來實現自己的aware接口了。Webx就是這么做的(webx本身作為一個容器,本身注冊了各類aware接口的BeanPostProcessor),比如我們想要感知到當前環境是否是生產模式,我們只需要實現ProductionModeAware接口就能夠獲得生產模式的值了。我們使用aware接口感覺很神奇很簡便,原因是很多工作框架已經幫我們做了。webx中使用ProductionModeAwarePostProcessor這個BeanPostProcessor來進行生產模式的注入。在postProcessBeforeInitialization方法中:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof ProductionModeAware) {
        ((ProductionModeAware) bean).setProductionMode(configuration.isProductionMode());
    }
 
    return bean;
}

所以任何實現了ProductionModeAware接口的類,在webx容器中都能夠獲得生產模式的取值。

三、自定義aware接口實現

  了解了個中原理,那么自定義aware接口實現起來並不復雜。我們只需要2步操作:1.實現我們aware接口的postprocessor,並在容器中注冊;2.bean實體類集成我們自定義的aware接口並實現。代碼如下:Aware接口比較簡單,就做一件事情,把Apple對象注入。

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());
    }
}

四、


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM