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

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 {

    @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 原理探究)