zoukankan      html  css  js  c++  java
  • Spring源码分析-事件机制

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

    一、示例

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

    控制台输出:

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

     

    二、源码分析

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

    2.Debug 运行测试类

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

     从这个线程栈中可以看出,执行到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) 方法

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

    查看线程栈

    首先是调用 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 
  • 相关阅读:
    些许注意事项(初学)
    第一个方法(初学)
    重载(初学)
    数组(初学)
    文件下载(初学)
    javaweb中上传视频,并且播放,用上传视频信息为例
    javaweb中上传图片并显示图片,用我要上传课程信息(里面包括照片)这个例子说明
    从后台servlet中,获取jsp页面输入的值,来删除用户一行信息
    第二式 观察者模式
    第一式 策略模式
  • 原文地址:https://www.cnblogs.com/caoxb/p/12490111.html
Copyright © 2011-2022 走看看