Spring内置事件和自定义事件

Spring内置事件和自定义事件

事件传递对象(ApplicationEvent)

ApplicationEnvironmentPreparedEvent

ApplicationEvent是事件接口,继承自EventObject(Java规范要求事件对象都需要继承该类)。

内置事件对象包括两部分:

  1. ApplicationContextEvent是Spring Framework需要的。
  2. SpringApplicationEvent该类在Spring boot包下。

事件监听(ApplicationListener)

MultiServerUserRegistry

ApplicationListener是Spring的事件监听接口,实现了jdk中的EventListener,该接口只提供了一个抽象方法void onApplicationEvent(E event)用于处理接收到的事件。

子接口SmartApplicationListener增加了两个抽象方法(supportsEventTypesupportsSourceType)并且还继承了Ordered接口提供监听器排序。

supportsEventTypesupportsSourceType两个方法都是过滤方法返回事件类型和事件源类型是否支持。

事件发布

ApplicationEventPublisher

AbstractApplicationContext

ApplicationEventPublisher事件发布接口,ApplicationContext接口继承了该接口,这也就说明Spring Framework的核心IoC容器都具有发布事件的能力,接口方法在AbstractApplicationContext中实现,来看一下实现代码:

/**
* 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");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}

// 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 {
//事件发布委派给ApplicationEventMulticaster类来完成
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);
}
}
}

从代码中可以看出事件发布实际上是委派给ApplicationEventMulticaster实例来做的,下面我们来看ApplicationEventMulticaster

ApplicationEventMulticaster

SimpleApplicationEventMulticaster

ApplicationEventMulticaster接口有一个抽象实现和一个简单实现,通过查看ApplicationEventMulticaster接口规范我们会发现改接口提供注册Listener和通知Listener的接口契约。

Spring内部的事件发布是通过ApplicationEvent#publishEvent再委派给ApplicationEventMulticaster实际去发送事件的。我们来看一下ApplicationEventMulticaster的实现逻辑。

  1. ApplicationEventMulticaster的实例化

    /**
    * 初始化ApplicationEventMulticaster.
    * 如果在IoC容器上下文中不存在以applicationEventMulticaster命名的ApplicationEventMulticaster Bean
    * 就使用新创建一个SimpleApplicationEventMulticaster,并注册到IoC容器中。
    *
    * 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.isDebugEnabled()) {
    logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    }
    } else {
    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 + "]");
    }
    }
    }
  2. SimpleApplicationEventMulticaster#multicastEvent()的实现

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    Executor executor = getTaskExecutor();
    //如果Executor如果不为空,那么将调用Executor的execute方法,发起异步通知
    if (executor != null) {
    executor.execute(() -> invokeListener(listener, event));
    }
    //否则同步通知
    else {
    invokeListener(listener, event);
    }
    }
    }

    从代码中可以看出,只要Executor不为空,通知将异步执行,否则同步执行通知,所以我们可以传递Executor对象让通知异步执行。

    • SpringBoot方式

      @Configuration
      @EnableAsync
      public class MulticasterAsyncConfig {

      @Bean
      public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
      executor.setCorePoolSize(10);
      executor.setMaxPoolSize(100);
      executor.setQueueCapacity(2000);
      return executor;
      }

      @Bean
      public ApplicationEventMulticaster applicationEventMulticaster(BeanFactory beanFactory) {
      SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(beanFactory);
      multicaster.setTaskExecutor(threadPoolTaskExecutor());
      return multicaster;
      }
      }
  • Spring XML方式

    <task:executor id="executor" pool-size="10" />  
    <!-- 名字必须是applicationEventMulticaster和messageSource是一样的,默认找这个名字的对象 -->
    <!-- 名字必须是applicationEventMulticaster,因为AbstractApplicationContext默认找个 -->
    <!-- 如果找不到就new一个,但不是异步调用而是同步调用 -->
    <bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
    <!-- 注入任务执行器 这样就实现了异步调用(缺点是全局的,要么全部异步,要么全部同步(删除这个属性即是同步)) -->
    <property name="taskExecutor" ref="executor"/>
    </bean>

    但是这种方式有个弊端就是通知要么是全部是同步要么全部是异步,不能根据需要决定是否异步,所以我们使用另一种方式实现通知消息异步。我们会在下一篇自定义事件中讲解

自定义事件

有了Spring的支持我们自定义事件是非常简单的。

  1. 自定义事件

    public class CustomEvent<T> extends ApplicationEvent {

    public CustomEvent(T source) {
    super(source);
    }
    }
  2. 自定义事件监听继承自ApplicationListener

    @Component
    public class CustomEventListener implements ApplicationListener<CustomEvent> {

    @Override
    public void onApplicationEvent(CustomEvent customEvent) {
    System.out.println("得到事件内容:" + customEvent.getSource());
    }
    }
  3. 自定义事件监听实现SmartApplicationListener

    • CustomSmartEventListener1 order=1
    @Component
    public class CustomSmartEventListener1 implements SmartApplicationListener {
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
    return StringUtils.equals(aClass.getName(),CustomEvent.class.getName());
    }

    @Override
    public boolean supportsSourceType(Class<?> aClass) {
    return StringUtils.equals(String.class.getName(),aClass.getName());
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
    System.out.println("接收到通知1:" + applicationEvent.getSource());
    }

    @Override
    public int getOrder() {
    return 1;
    }
    }
    • CustomSmartEventListener2 order=2
    @Component
    public class CustomSmartEventListener2 implements SmartApplicationListener {
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
    return StringUtils.equals(aClass.getName(),CustomEvent.class.getName());
    }

    @Override
    public boolean supportsSourceType(Class<?> aClass) {
    return StringUtils.equals(String.class.getName(),aClass.getName());
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
    System.out.println("接收到通知2:" + applicationEvent.getSource());
    }

    @Override
    public int getOrder() {
    return 2;
    }
    }
  4. 事件发布

    @Autowired
    private ApplicationContext applicationContext;

    @GetMapping("/")
    public String index(){
    applicationContext.publishEvent(new CustomEvent<>("收到消息了吗?"));
    return "/index";
    }
  5. 输出结果:

    得到事件内容:收到消息了吗?
    接收到通知1:收到消息了吗?
    接收到通知2:收到消息了吗?

    从输出接口可以看到order越小监听器越早被调用。

参考

https://jinnianshilongnian.iteye.com/blog/1902886

文章作者: 平常心
文章链接: http://blog.v5cn.cn/2019/01/14/spring-event/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 平常心