Spring 源码解析 —- 事件监听

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

一. 测试用例

    package main.java.com.wenniuwuren.spring.event.listener;

    import org.springframework.context.ApplicationEvent;

    /**
     * 定义监听事件
     * Created by hzzhuyibin on 2016/11/22.
     */
    public class TestEvent extends ApplicationEvent {

    public String msg;

     /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
     public TestEvent(Object source) {
    super(source);
     }

    public TestEvent(Object source, String msg) {
    super(source);
     this.msg = msg;
     }

    public void print() {
    System.out.println(msg);
     }

    }
    package main.java.com.wenniuwuren.spring.event.listener;

    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;

    /**
     * 定义监听器
     * Created by hzzhuyibin on 2016/11/22.
     */
    public class TestListener implements ApplicationListener{
    @Override
     public void onApplicationEvent(ApplicationEvent event) {

    if (event instanceof TestEvent) {
    TestEvent testEvent = (TestEvent)event;
     testEvent.print();
     }
    }
    }

listenerTest.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean name="testListener" class="main.java.com.wenniuwuren.spring.event.listener.TestListener"/>

    </beans>

测试类:

    package main.java.com.wenniuwuren.spring.event.listener;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    /**
     *
     * Created by Yibin_Zhu on 2016/11/21.
     */
    public class Test{

        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("main/resources/listenerTest.xml");
            // 不仅仅可以指定 beanName,也可以有构造函数或者工厂方法的方法参数

            TestEvent testEvent = new TestEvent("hello", "wenniuwuren");

            context.publishEvent(testEvent);

        }
    }

二. 源码解析 debug 到 AbstractApplicationContext 类的 initApplicationEventMulticaster() 方法

广播器我们又经常成为事件

    protected void initApplicationEventMulticaster() {
       ConfigurableListableBeanFactory beanFactory = getBeanFactory();
       // 用户自定义事件广播器
       if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
          this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
          if (logger.isDebugEnabled()) {
             logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
          }
       }
       else { // 默认事件广播器
          this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
          beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
          if (logger.isDebugEnabled()) {
             logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                   APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                   "': using default [" + this.applicationEventMulticaster + "]");
          }
       }
    }

我们关注的是 SimpleApplicationEventMulticaster 事件类的具体实现,继续 debug 进去,看到此类继承自 AbstractApplicationEventMulticaster, 而 AbstractApplicationEventMulticaster 中有许多 add**Listener、delete**Listener 之类的方法,可以知道这是典型的
观察者模式的应用。

继续看如下方法:事件在这里广播,遍历所有监听器,通知监听器

    @Override
    public void multicastEvent(ApplicationEvent event) {
       multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
       ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
       for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
          Executor executor = getTaskExecutor();
          if (executor != null) {
             executor.execute(new Runnable() {
                @Override
                public void run() {
                   invokeListener(listener, event);
                }
             });
          }
          else {
             invokeListener(listener, event);
          }
       }
    }

    protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
       ErrorHandler errorHandler = getErrorHandler();
       if (errorHandler != null) {
          try {
             listener.onApplicationEvent(event);
          }
          catch (Throwable err) {
             errorHandler.handleError(err);
          }
       }
       else {
          listener.onApplicationEvent(event);
       }
    }

这个方法 debug 结束,回到 AbstractApplicationContext 类,debug 进 registerListeners() 方法:注册监听器

    protected void registerListeners() {
       // 硬编码的方式注册监听器
       for (ApplicationListener<?> listener : getApplicationListeners()) {
          getApplicationEventMulticaster().addApplicationListener(listener);
       }

       // 配置文件注册监听器
       String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
       for (String listenerBeanName : listenerBeanNames) {
          getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
       }

       // Publish early application events now that we finally have a multicaster...
       Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
       this.earlyApplicationEvents = null;
       if (earlyEventsToProcess != null) {
          for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
             getApplicationEventMulticaster().multicastEvent(earlyEvent);
          }
       }
    }

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring 源码解析 —- 事件监听

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏