04.Spring监听器

Spring思维导图

Spring事件

Spring事件体系包括三个组件:事件,事件监听器,事件广播器

首先需要了解什么是:观察者模式

事件

Spring 内置事件

04.Spring监听器

Event 说明
ContextRefreshedEvent 当容器被实例化或refreshed时发布.如调用refresh()方法, 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化, 所有的容器对象都已准备好可使用. 如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)利用此内置事件可以在所有的Bean都创建完成后做扩展代码
ContextStartedEvent 当容器启动时发布,即调用start()方法, 已启用意味着所有的Lifecycle bean都已显式接收到了start信号
ContextStoppedEvent 当容器停止时发布,即调用stop()方法, 即所有的 Lifecycle bean都已显式接收到了stop信号 , 关闭的容器可以通过start()方法重启
ContextClosedEvent 当容器关闭时发布,即调用close方法, 关闭意味着所有的单例bean都已被销毁.关闭的容器不能被重启或refresh
RequestHandledEvent 这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布

自定义事件

1、事件类继承 ApplicationEvent,构造方法 super(Object source)

// 事件类继承 ApplicationEvent ,构造方法 super
public class OrderEvent  extends ApplicationEvent implements Serializable {

   private static final long serialVersionUID = -724777220496990061L;
   private String name;

    public OrderEvent(Object source, String name) {
        super(source);
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

2、事件监听器 又分为两种(基于接口、基于注解) ,需要是 Spring 容器托管的 bean 需要加上 @Component 注解,只有一个方法 onApplicationEvent

基于接口:

@Component
@Lazy
public class OrderEventListener implements ApplicationListener<OrderEvent> {
	
	@Override
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("Inventory reduction")){
            System.out.println("Inventory reduction.......");
        }
    }

}

基于注解:

@Component
@Lazy
public class OrderEventListener {
    
    // 基于注解的
    @EventListener(OrderEvent.class)
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("Inventory reduction")){
            System.out.println("Inventory reduction.......");
        }
    }

}

3、发布事件 publishEvent((ApplicationEvent event)

public class MainClass {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig2.class);

		//下单
		Order order =new Order();
		order.setId(1);
		System.out.println("place the order");
		// 减库存
         // 发布事件 
		ctx.publishEvent(new OrderEvent(order,"Inventory reduction"));
		// 日志
		System.out.println("other...");
	}
}
---------------运行结果-----------------
place the order
Inventory reduction.......
other...

04.Spring监听器

注意的点:

  • 同样的事件能有多个监听器
  • 事件监听操作和发布事件的操作是同步的,如果有事务,监听操作也在事务内
  • 事件可以作为异步处理

04.Spring监听器

Spring 源码解析

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

04.Spring监听器

refresh()方法中有两个监听器相关的方法,分别是

  • 创建事件多播器
    initApplicationEventMulticaster(); 提供了容器监听器的注册表
  • 将事件监听器注册到多播器上
    registerListeners();
try {
   // 4:空方法
   // 留给子类去实现该接口 允许在上下文子类中对Bean工厂进行后置处理。
   postProcessBeanFactory(beanFactory);

   // 5:调用Bean工厂的后置处理器
   // 执行自定义的BeanFactoryPostProcessor和内置的BeanFactoryPostProcessor
   // 此方法会实例化几个内置的Bean实例化
   invokeBeanFactoryPostProcessors(beanFactory);

   // 6:调用Bean的后置处理器,此处也会实例化几个内置的Bean
   registerBeanPostProcessors(beanFactory);

   // 7:初始化国际化资源处理器.
   initMessageSource();

   // 8:创建事件多播器
   initApplicationEventMulticaster();

   // 9:这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
   onRefresh();

   // 10:将事件监听器注册到多播器上
   registerListeners();

   // 11:实例化懒加载单例Bean的,也就是我们的Bean都是在这里被创建出来的(绝大部分情况)
   finishBeanFactoryInitialization(beanFactory);

   // 12:最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
   finishRefresh();
}

1、事件广播器的初始化

/**
 * 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 + "]");
        }
    }
}

用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster就可以了,Spring 会通过反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring 自动使用SimpleApplicationEventMulticaster作为事件广播器。

2、注册事件监听器

/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
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!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

Spring 根据反射机制,使用 ListableBeanFactory 的getBeansOfType()方法,从 BeanDefinitionRegistry 中找出所有实现org.springframework.context.ApplicationListener的 Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。

3、发布事件

跟着finishRefresh();方法进入publishEvent(new ContextRefreshedEvent(this));方法如下:

/**
 * 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, 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<Object>(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);
        }
    }
}

在AbstractApplicationContext的publishEvent()方法中, Spring 委托 ApplicationEventMulticaster 将事件通知给所有的事件监听器.

4 、Spring默认的事件广播器SimpleApplicationEventMulticaster

@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    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
 */
@SuppressWarnings({"unchecked", "rawtypes"})
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
        }
    }
}

遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent方法。由于SimpleApplicationEventMulticaster的taskExecutor的实现类是 SyncTaskExecutor,因此,事件监听器对事件的处理,是同步进行的

从源码可以看出applicationContext.publishEvent()方法,需要同步等待各个监听器处理完之后,才返回。也就是说,Spring 提供的事件机制,默认是同步的。如果想用异步的,可以自己实现ApplicationEventMulticaster接口,并在Spring 容器中注册 id 为 applicationEventMulticaster 的 Bean。

public class AsyncApplicationEventMulticaster extends AbstractApplicationEventMulticaster {  
    private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();  

    public void setTaskExecutor(TaskExecutor taskExecutor) {  
        this.taskExecutor = (taskExecutor != null ? taskExecutor : new SimpleAsyncTaskExecutor());  
    }  

    protected TaskExecutor getTaskExecutor() {  
        return this.taskExecutor;  
    }  

    public void multicastEvent(final ApplicationEvent event) {  
        for (Iterator<ApplicationListener> it = getApplicationListeners().iterator(); it.hasNext();) {  
            final ApplicationListener listener =  it.next();  
            getTaskExecutor().execute(new Runnable() {  
                public void run() {  
                    listener.onApplicationEvent(event);  
                }  
            });  
        }  
    }  
}  
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
    SimpleApplicationEventMulticaster eventMulticaster
            = new SimpleApplicationEventMulticaster();

    //ThreadPoolTaskExecutor
    eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
    return eventMulticaster;
}

Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。Sping 事件体系所使用的设计模式是:观察者模式。ApplicationListener 是观察者接口,接口中定义了onApplicationEvent()方法,该方法的作用是对 ApplicationEvent 事件进行处理。

上一篇:echarts柱状图tooltip之formatter调试技巧


下一篇:2.11 JavaWeb核心之Listener