spring源碼:ApplicationContext的加強功能(li)

              ApplicationContext做爲資源加載器;ApplicationContext做爲事件發佈者;java

  Java原生提供了事件發佈機制------EventObject對象做爲發佈的事件,EventListener做爲處理髮布事件的監聽器。可是其並無提供發佈者的角色來橋接EventObject和EventListener。Spring對java原生的事件發佈機制作了擴展:一方面擴展了EventObject和EventListener,使其能夠記錄事件發佈時間,擴展了事件發佈接口;更重要的一點,ApplicationContext自身能夠充當事件發佈者(由於其實現了ApplicationEventPublisher接口),完成了本應該由開發者來實現的代碼(若是使用java原生髮布事件機制的話)。當對象A(被觀察者)發生變化時,有一個發佈者(能夠是被觀察者自身,也能夠委託第三方如spring容器)發出通知,事物B(觀察者)可以收到通知更新本身的狀態。這個就是常常使用到的觀察者模式,spring容器提供了這種觀察者模式的支持。咱們經過一個例子來講明如何在Spring框架中使用事件發佈,並能讓觀察者(listener)獲得消息。首先,自定義咱們的EventObject,做爲發佈者和監聽者之間約定好的事件對象。spring

public class MyEvent extends ApplicationEvent {
 
    /**
     *
     */
    private static final long serialVersionUID = 1L;
 
    /**
     * @param source
     */
    public MyEvent(Object source){
        super(source);
        // TODO Auto-generated constructor stub
    }
 
}

自定義的MyEvent繼承了ApplicationEvent,ApplicationEvent類是spring框架繼承EventObject而來,加入了獲取發佈時間的方法。其次,自定義咱們的EventListener,它負責監聽容器發佈的ApplicationEvent事件並進行處理:app

public class MyListener implements ApplicationListener {
 
    /* (non-Javadoc)
     * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof MyEvent) {
            System.out.println(event == null ? "" : event.getSource());
        }
    }
 
}

由於咱們只關心MyEvent事件的發佈,因此在onApplicationEvent方法中進行了判斷,過濾其餘不相關發佈事件。定義完了事件和監聽器,基本就剩下發布事件的代碼了。發佈者由ApplicationContext來充當:框架

public class TestPublisher {
    public static void main ( String args[] ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // applicationContext.xml配置文件中已經配置好了監聽器
        ctx.publishEvent(new MyEvent("Hello World")); // 發佈事件,監聽器接收到事件消息
    }
}

最後,不要忘記在配置文件中添加監聽對象:ide

<bean class="com.alibaba.china.publisher.MyListener" />

spring容器會自動加載配置文件中全部的ApplicationListener對象,把它註冊到觀察者列表中。當有事件發佈的時候,就從這個觀察者列表中挨個通知事件發佈。程序執行結果以下: post

其餘細節點:spa

  1. ApplicationContext自動加載全部的Bean ApplicationContext自動加載全部的Bean;
  2. ApplicationContext自動識別BeanFactoryPostProcessor,BeanPostProcessor,並註冊到容器中。

  ApplicationContext自動加載全部的Bean:ApplicationContext相對於BeanFactory不一樣的一點是,BeanFactory在用到Bean的時候纔會去加載bean(在beanFactory.getBean(「beanName」)以前不會加載beanName的對象)。而ApplicationContext不一樣,在容器建立時就已經把全部的Bean加載進容器了。code

  ApplicationContext自動識別BeanFactoryPostProcessor,BeanPostProcessor,並註冊到容器中:BeanFactoryPostProcessor是容器在加載完BeanDefinition以後,容器初始化以前對beanFactory作處理的一個擴展機制。好比咱們的antx配置項替換類PropertyPlaceholderConfigurer。咱們只須要在配置文件中聲明PropertyPlaceholderConfigurer這類BeanFactoryPostProcessor對象,ApplicationContext就可以識別出來並自動將這些processor註冊到容器中。BeanPostProcessor也是一樣的道理,ApplicationContext可以自動識別xml中配置好的這類bean並進行容器的註冊。BeanFactory就不能這麼簡潔了,必須咱們手動去把那些BeanFactoryPostProcessor以及BeanPostProcessor對象註冊到容器中。ApplicationContext可以本身感知到這些processor,咱們的工做只是去實現自定義的(或者直接使用spring已經實現了的)BeanFactoryPostProcessor和BeanPostProcessor,並在配置文件中聲明。是否是以爲很神奇?ApplicationContext能作到感知的緣由就在於其對mdb(Merged BeanDefinition)的處理。xml

org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)實現:
 
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// beanFactory的getBeanNamesForType方法可以根據對象的類型(此處是BeanFactoryPostProcessor.class),從mdb中找到他們的beanName
String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
......
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
Collections.sort(priorityOrderedPostProcessors, new OrderComparator());
// 這裏全部聲明在配置文件中的BeanFactoryPostProcessor都被調用,執行接口的postProcessBeanFactory方法。
invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);

上面的代碼中會從mdb中找出BeanFactoryPostProcessor接口的對象,並對它們進行排序,而後根據這些BeanFactoryPostProcessor依次對beanFactory處理。對象

相關文章
相關標籤/搜索