为了方便快速理解,我还是先不讲原理,直接示例开篇吧。

一、示例

1.定义一个Listener 实现了ApplicationListener 接口

@Component
public class MyTestListener implements ApplicationListener{

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("向zookeeper注册暴露的服务...");
    }
}

 

2.applicationContext.xml 添加如下内容

<context:annotation-config />
<context:component-scan base-package="com.event" />

 

3.测试

public class SpringEventTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }
}

 

控制台输出:

Spring源码分析-事件机制

在这里不知道大家有没有发现,我这个main方法除了new ClassPathXmlApplicationContext("classpath:applicationContext.xml");其它什么也没做,那么为何MyTestListener 中的 onApplicationEvent 方法就执行了?

 

二、源码分析

1.先在自定义的listener类的 onApplicationEvent 方法进行断点调试(这里主要是为了通过Debug模式的线程栈查看 从执行main方法开始到最后执行onApplicationEvent 方法结束都调用了哪些方法

Spring源码分析-事件机制

 

2.Debug 运行测试类

 

3.通过 Debug 线程栈分析源码执行过程(这里展示从main方法开始到onApplicationEvent方法的调用过程

Spring源码分析-事件机制

 

 从这个线程栈中可以看出,执行到refresh 方法中的finishRefresh 时,即执行publishEvent,关于refresh 方法我在这里不做过多的说明。

 AbstractApplicationContext 类中的 refresh 方法部分源码如下:

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try {
            // 省略若干代码...
            onRefresh();
            // Check for listener beans and register them.
            // 核心代码:事件注册
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            // 核心代码:执行发布事件
            finishRefresh();
        }
    }
}

 

protected void finishRefresh() {
    // Initialize lifecycle processor for this context.
    initLifecycleProcessor();
    // Propagate refresh to lifecycle processor first.
    getLifecycleProcessor().onRefresh();
    // 发布事件
    publishEvent(new ContextRefreshedEvent(this));
    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

 

@Override
public void publishEvent(ApplicationEvent event) {
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }
    // getApplicationEventMulticaster() 得到的是 SimpleApplicationEventMulticaster 对象
    getApplicationEventMulticaster().multicastEvent(event);
    if (this.parent != null) {
        this.parent.publishEvent(event);
    }
}

 

我们再进入到 SimpleApplicationEventMulticaster 中的 multicastEvent方法

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

for 循环中 getApplicationListeners(event) 方法获取的就是所有的Listener,这里也就是遍历所有的listener,然后执行下面的 invokeListener 方法

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

这个方法很明显后面直接调用了 onApplicationEvent,也就是说当这个listener 为自定义的 MyTestListener 时,就会 MyTestListener 中的 onApplicationEvent 方法。

到这里我们也就就搞清楚了onApplicationEvent 如何执行的。

那么问题来了,上面的for 循环中 getApplicationListeners(event) 要得有 MyTestListener 这个类型的实例,才会最终执行onApplicationEvent 方法的?

我们先来看一下 AbstractApplicationEventMulticaster 类中的 getApplicationListeners(event) 方法

Spring源码分析-事件机制

 

我们在 AbstractApplicationEventMulticaster 类中找到了如下图所示这两个方法,并且我们开始在这两个方法上开始打上断点进行调试

Spring源码分析-事件机制

查看线程栈

Spring源码分析-事件机制

首先是调用 refresh 方法中的 registerListeners 方法(这个方法在finishRefresh 方法之前就执行了),我们来看一下registerListeners 

protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // getBeanNamesForType 方法其实就是获取 ApplicationListener 这种类型的 所有bean定义的name
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String lisName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(lisName);
    }
}

 

 

事件bean注册

@Override
public void addApplicationListenerBean(String listenerBeanName) {
    synchronized (this.defaultRetriever) {
        // 注册
        this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
        this.retrieverCache.clear();
    }
}

从 getBeanNamesForType 方法也可以看出取出来的是bean定义的name,即这个Listener 是一个bean,这也就是为什么要在MyTestListener类上加一个注解@Component。

 

总结:只要你定义的某个类 实现ApplicationListener 接口,并且放入了spring 的 bean容器中,最终是会调用这个onApplicationEvent 方法;

 

三、应用场景

 

1.dubbo 框架中的 ServiceBean 
ServiceBean 实现了 ApplicationListener 接口。当服务端执行main方法时(通过spring容器调用start 方法,其实也就是执行refresh方法),在不做代码入侵的情况下,dubbo通过ServiceBean 中的 onApplicationEvent 向注册中心注册暴露的服务。
 
2.mybatis框架中的 SqlSessionFactoryBean 

 

相关文章:

  • 2021-12-09
  • 2021-08-02
  • 2021-09-01
  • 2021-12-15
  • 2021-04-21
  • 2022-12-23
猜你喜欢
  • 2021-09-25
  • 2021-08-27
  • 2019-06-18
  • 2022-12-23
  • 2021-12-19
  • 2021-07-20
  • 2021-11-25
相关资源
相似解决方案