Spring事件机制

1. 使用Spring 事件

首先spring事件分为事件发布者(EventPublisher)、事件监听者(EventListener),还包括一个事件广播者(这个是spring实现相关,这一节不讨论)。使用spring事件机制,需要自定义事件发布者和监听者。
以一个简单的例子开始,事件发布者发送一个string类型的消息,接受者将接收到的消息打印出来。

  1. 事件发布者
@Component
public class SaySomethingPublisher implements ApplicationEventPublisherAware{
    private ApplicationEventPublisher applicationEventPublisher;

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void saySomething(String msg){
        applicationEventPublisher.publishEvent(msg);
    }
}

需要实现ApplicationEventPublisherAware这个Aware接口,广播事件需要利用applicationEventPublisher

关于ApplicationEventPublisherAware如下:

public interface ApplicationEventPublisher {
    void publishEvent(ApplicationEvent event);
    void publishEvent(Object event);
}

用户发布的事件类型可以是:
1. 用户可以继承ApplicationEvent从而自定义Event类型
2. 也可以使用任意Object类型,但是如果event真实类型不是ApplicationEvent的话,那么event会被封装成PayloadApplicationEvent
  1. 事件监听者

//事件监听者需要实现ApplicationListener接口
@Component
public class ListenerA implements ApplicationListener> {
    // 由于监听的是String类型的事件会被封装成PayloadApplicationEvent,所以此处类型是PayloadApplicationEvent
    public void onApplicationEvent(PayloadApplicationEvent event) {
        // getSource返回真实的事件
        Object msg = event.getSource();
        System.out.println("ListenerA receive:" + msg);
    }
}

关于发布出去的事件,那些监听者会监听到?

  1. 发布的事件类型是ApplicationEvent的实现类A
    那么所有监听者的onApplicationEvent的参数类型是A或者A的子类都会收到事件。
  2. 发布的事件类型是不是ApplicationEvent类型,类型是B
    这种情况下,最终事件会被包装成PayloadApplicationEvent, 那么所有监听者方法onApplicationEvent的参数是PayloadApplicationEvent的监听者会收到, 假设有C是B的父类,且有一个监听者X监听PayloadApplicationEvent,那X是收不到PayloadApplicationEvent类型的事件的

2. Spring事件原理

Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:

Spring事件机制_第1张图片
Spring事件机制

也就是说上面代码中发布者调用applicationEventPublisher.publishEvent(msg); 是会将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。

2.1 EventMultiCaster

ApplicationContext完成bean的装配和初始化后(非lazy-init的singleton bean会加载后就初始化),会尝试创建一个eventMultiCaster,创建代码如下:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //判断有没有一个name是“applicationEventMulticaster”且实现了“ ApplicationEventMulticaster”的bean,有的话那它就是eventMultiCaster
        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 {
            // 没有这样一个bean,那就会创建一个默认的
            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 + "]");
            }
        }
}
  1. 默认SimpleApplicationEventMulticaster
    直接看一下SimpleApplicationEventMulticaster用来广播event的代码:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
                // 这个是用来根据event的类型找到合适的listener的
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener listener : getApplicationListeners(event, type)) {
                        
            Executor executor = getTaskExecutor();
            // executor不是空的时候会在executor中激活listener
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            // 否则就直接在当前调用线程中激活listener 
            else {
                invokeListener(listener, event);
            }
        }
}

在创建SimpleApplicationEventMulticaster时,executor是null,所以默认情况下所有的listener 的onApplicationEvent是直接在当前线程(事件发布者所在线程)中调用,所以
如果onApplicationEvent有阻塞操作也会导致事件发布者被阻塞,后续的其他listener也会被阻塞无法调用。

  1. 自定义multicaster
    「2.1」中介绍spring会加载一个叫applicationEventMulticaster且实现了ApplicationEventMulticaster接口的multicaster,自定义multicaster需要实现了该接口然后将bean的名字设为applicationEventMulticaster即可。
    下面的例子为默认的SimpleApplicationEventMulticaster添加了executor,以使事件发布者和监听者不用在同一个线程中调用:
//使用线程池运行listener

 


       
       

3. 附

  1. Spring启动完成之后(已经完成bean解析,non-lazy-init的singleton实例化和初始化,完成listener的注册),默认会发布一个ContextRefreshedEvent事件,该事件包装的消息是一个ApplicationContext对象。

你可能感兴趣的:(Spring事件机制)