美文网首页
Spring 事件监听——ApplicationListener

Spring 事件监听——ApplicationListener

作者: lemontree93 | 来源:发表于2020-04-13 22:57 被阅读0次

    Spring 事件监听——ApplicationListener 原理探究

    最近项目中看到有人用 ApplicationListener ,注释上说是异步执行,某同事说该异步调用就是个笑话。今天有空研究了下。

    具体实现

    1. 定义事件监听器:定义ApplicationListener的实现类
    2. 定义事件Event:继承ApplicationEvent,具体的业务参数是绑定到事件中的
    3. 推送事件:applicationContext.pushEvent

    定义事件监听器,在监听器中实现具体业务逻辑

    /**
     * @program: demo
     * @author: Mr.Lemon
     * @create: 2020/4/12
     **/
    @Component
    public class DemoApplicationListener implements ApplicationListener<MyEvent> {
    
        @Override
        public void onApplicationEvent(MyEvent event) {
            String s = null;
            System.out.println("do listener");
            s.toString();
        }
    }
    
    

    定义事件Event,将参数传入到监听器中

    /**
     * @program: demo
     * @author: Mr.Lemon
     * @create: 2020/4/12
     **/
    public class MyEvent extends ApplicationEvent {
    
        /**
         * Create a new {@code ApplicationEvent}.
         *
         * @param source the object on which the event initially occurred or with
         *               which the event is associated (never {@code null})
         */
        public MyEvent(Object source) {
            super(source);
        }
    }
    
    

    推送事件,推送事件,触发监听动作

        @Autowired
        private ApplicationContext applicationContext;
        
        @GetMapping("/push")
        public String pushEvent() {
            applicationContext.publishEvent(new MyEvent("111"));
            return "ok";
        }
    

    源码实现

    实现非常简单,没什么好说的,接下来看下源码实现,从applicationContext.publishEvent入手。

        /**
         * Publish the given event to all listeners.
         * @param event the event to publish (may be an {@link ApplicationEvent}
         * or a payload object to be turned into a {@link PayloadApplicationEvent})
         * @param eventType the resolved event type, if known
         * @since 4.2
         */
        protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
            Assert.notNull(event, "Event must not be null");
    
            // Decorate event as an ApplicationEvent if necessary
            ApplicationEvent applicationEvent;
            if (event instanceof ApplicationEvent) {
                applicationEvent = (ApplicationEvent) event;
            }
            else {
                applicationEvent = new PayloadApplicationEvent<>(this, event);
                if (eventType == null) {
                    eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
                }
            }
    
            // Multicast right now if possible - or lazily once the multicaster is initialized
            if (this.earlyApplicationEvents != null) {
                this.earlyApplicationEvents.add(applicationEvent);
            }
            else {
                getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
            }
    
            // Publish event via parent context as well...
            if (this.parent != null) {
                if (this.parent instanceof AbstractApplicationContext) {
                    ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
                }
                else {
                    this.parent.publishEvent(event);
                }
            }
        }
    

    具体的实现应该是在 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

    继续往下走

        @Override
        public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
            ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
            Executor executor = getTaskExecutor();
            for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                if (executor != null) {
                    executor.execute(() -> invokeListener(listener, event));
                }
                else {
                    invokeListener(listener, event);
                }
            }
        }
        
        /**
         * Invoke the given listener with the given event.
         * @param listener the ApplicationListener to invoke
         * @param event the current event to propagate
         * @since 4.1
         */
        protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
            ErrorHandler errorHandler = getErrorHandler();
            if (errorHandler != null) {
                try {
                    doInvokeListener(listener, event);
                }
                catch (Throwable err) {
                    errorHandler.handleError(err);
                }
            }
            else {
                doInvokeListener(listener, event);
            }
        }
    

    可以这里很关键,可以看到有个 Executor executor = getTaskExecutor(); 所以其实可以得到结论了:事件的监听执行是可以异步进行的,那么接下来研究下如何实现异步。

    异步执行事件监听

    Executor executor = getTaskExecutor();
    是在 org.springframework.context.event.SimpleApplicationEventMulticaster#getTaskExecutor

    那么,这个类是在什么时候进行定义的?回忆下springboot的启动过程:

    SpringBoot.run -> org.springframework.boot.SpringApplication#refreshContext -> org.springframework.boot.SpringApplication#refresh

    这里截取部分代码

                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh();
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    
    

    可以看到上面有个 initApplicationEventMulticaster();

                
        /**
         * Name of the ApplicationEventMulticaster bean in the factory.
         * If none is supplied, a default SimpleApplicationEventMulticaster is used.
         * @see org.springframework.context.event.ApplicationEventMulticaster
         * @see org.springframework.context.event.SimpleApplicationEventMulticaster
         */
        public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
        
        /**
         * Initialize the ApplicationEventMulticaster.
         * Uses SimpleApplicationEventMulticaster if none defined in the context.
         * @see org.springframework.context.event.SimpleApplicationEventMulticaster
         */
        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.isTraceEnabled()) {
                    logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
                }
            }
            else {
                this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
                beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
                if (logger.isTraceEnabled()) {
                    logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                            "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
                }
            }
        }
    
    

    解读下代码就是:如果容器定义了 applicationEventMulticaster 的bean,那么 applicationEventMulticaster 的具体实现就是该类,否则就是 SimpleApplicationEventMulticaster,所以,思路很简单了,我只要定义一个类,继承 SimpleApplicationEventMulticaster,然后在给 taskExecutor 赋值就行了

    /**
     * @program: demo
     * @author: Mr.Lemon
     * @create: 2020/4/12
     **/
    @Component("applicationEventMulticaster")
    public class DemoMulticaster extends SimpleApplicationEventMulticaster {
        
        public DemoMulticaster(){
            setTaskExecutor(Executors.newSingleThreadExecutor());
        }
    }
    

    总结

    Spring的事件监听是可以实现异步的,只是需要对原本的类进行拓展

    相关文章

      网友评论

          本文标题:Spring 事件监听——ApplicationListener

          本文链接:https://www.haomeiwen.com/subject/dpaomhtx.html