Spring 事件

274 阅读5分钟

Spring 事件

abstract ApplicationEvent extends EventObject

abstract ApplicationContextEvent extends ApplicationEvent

​ ApplicationContext 作为数据源,方便后续的交互

具体实现

ContextClosedEvent

ContextRefreshedEvent

ContextStartedEvent

ContextStoppedEvent

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

   /**
    * Handle an application event.
    * @param event the event to respond to
    */
   void onApplicationEvent(E event);

}

代码示例

context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        println("ApplicationListener - 接收到 Spring 事件:" + event);
    }
});
//或者,将ApplicationListener注册为Bean,同样也能够接收到事件
context.register(new MyApplicationListener())

ApplicationContext#refresh() , 会将所有的ApplicationListener添加到一个集合中

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);
      }
   }
}

所以通过addApplicationListener 和 将ApplicationListener注册成为Bean都可以接收到事件。

@EventListener

public @interface EventListener {

   @AliasFor("classes")
   Class<?>[] value() default {};
  
   @AliasFor("value")
   Class<?>[] classes() default {};
  
   String condition() default "";

}

代码示例

@EventListener
public void onApplicationEvent(ApplicationEvent event) {
    println("@EventListener - 接收到 Spring 事件:"+event);
}

@EventListener ——> ApplicationListener . 两个事件先后触发(多个,refresh、start、close等)

@Async 可以使事件异步触发。(标明 @EnableAsync)

@Order 配合控制事件优先级,数值越小,优先级越高

Spring 事件发布器

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

实现 ApplicationEventPublisherAware ,重写 setApplicationEventPublisher ,通过注入拿到 ApplicationEventPublisher 对象

@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    applicationEventPublisher.publishEvent(new ApplicationEvent("Hello,World") {
    });//默认的重载方法,指定类型为 ApplicationEvent
    // 发送 PayloadApplicationEvent
    applicationEventPublisher.publishEvent("Hello,World");//不指定类型,Spring 默认实现为PayloadApplicationEvent
    applicationEventPublisher.publishEvent(new MyPayloadApplicationEvent(this, "Hello,World"));
}

注:ApplicationContext 可以指定 parent , 在自己发送完事件的时候,还会去询问是否有parent ,如果有会通过parent再次发送当前的Event,这里需要小心的是,虽然是通过parent来发送,但是,事件还是当前Context的,所以,还是会有当前的Context来接收,而不是parent。所以会导致一个事件两次处理,就需要在开发中自己过滤掉已经处理过的事件,避免重复处理。

AbstarctApplicationContext#publishEvent
// 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);
  }
}
ApplicationEventMulticaster
public interface ApplicationEventMulticaster {
   void addApplicationListener(ApplicationListener<?> listener);
   void addApplicationListenerBean(String listenerBeanName);
   void removeApplicationListener(ApplicationListener<?> listener);
   void removeApplicationListenerBean(String listenerBeanName);
   void removeAllListeners();
   /**
    * Multicast the given application event to appropriate listeners.
    * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
    * if possible as it provides better support for generics-based events.
    * @param event the event to multicast
    */
   void multicastEvent(ApplicationEvent event);//广播给定的事件到合适的listeners
   /**
    * Multicast the given application event to appropriate listeners.
    * <p>If the {@code eventType} is {@code null}, a default type is built
    * based on the {@code event} instance.
    * @param event the event to multicast
    * @param eventType the type of event (can be {@code null})
    * @since 4.2
    */
   void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);//eventType 匹配事件
}

这个接口是Spring 事件的底层实现。在 AbstractApplicationContext这个类里面有这样的方法 addApplicationListener 内部实现是这样的:

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
   Assert.notNull(listener, "ApplicationListener must not be null");
   if (this.applicationEventMulticaster != null) {
      this.applicationEventMulticaster.addApplicationListener(listener);
   }
   else {
      this.applicationListeners.add(listener); //后续还是通过applicationEventMulticaster处理的
   } 
}

可以看出来,内部是委派给了 ApplicationEventMulticaster 去处理的。

earlyApplicationEvents
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   ....
   // 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);
   }
   ....
}

这里需要注意的是在 ApplicationMulticaster还没有初始化的时候,定义了一个集合用来存储在初始化之前的事件。这种情况很少见,但是会有这样的情况出现。比如说,一个 Configuration Class ,同时实现了 BeanPostProcessorApplicationEventPublisherAware 就会出现事件早于ApplicationMulticaster初始化的发生。

#AbstractApplicationContext
	registerBeanPostProcessors()
#PostProcessorRegistrationDelegate
	registerBeanPostProcessors()
#AbstractBeanFactory
	doGetBean()
....
#AbstractAutowireCapableFactory
	applyBeanPostProcessorsBeforeInitialization()
#ApplicationContextAwareProcessor
	postProcessBeforeInitialization()
	
 //最后会回调 实现了 ApplicationEventPublisherAware
  private void invokeAwareInterfaces(Object bean) {
		....
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
  	....
	}

这整个的过程起始点在 AbstractApplicationContext#refresh() ,在这个方法里会先后调用 registerBeanPostProcessors()initApplicationEventMulticaster() ,所以就会出现上述所说的有些事件会先于 ApplicationMulticaster的初始化。

@EventListener
@EventListener
public void onEvent(MySpringEvent event) {
    System.out.printf("[线程 : %s] onEvent方法监听到事件 : %s\n", 			       Thread.currentThread().getName(), event);
}

context.publishEvent(new MySpringEvent("Hello,World"));

以上代码便是注解的方式实现事件的监听。这个注解的处理主要是由 EventListenerMethodProcessor 这个 BeanFactoryPostProcessor 来负责的。

EventListenerMethodProcessor#processBean

for (Method method : annotatedMethods.keySet()) {
   for (EventListenerFactory factory : factories) {
      if (factory.supportsMethod(method)) {
         Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); //拿到@EventListener注解标注的 onEvent方法
         ApplicationListener<?> applicationListener =
               factory.createApplicationListener(beanName, targetType, methodToUse);
        //factory 指的是 EventListenerFactory 默认实现类 DefaultEventListenerFactory
        //factory.createApplicationListener 得到的是 ApplicationListenerMethodAdapter
        //ApplicationListenerMethodAdapter 实现了 ApplicationListener
        //ApplicationListenerMethodAdapter内部会去处理 优先级、类的类型(Resolvable)、Reactive等
         if (applicationListener instanceof ApplicationListenerMethodAdapter) {
            ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
         }
         context.addApplicationListener(applicationListener);
         break;
      }
   }
}

DefaultEventListenerFactory
@Override
	public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
		return new ApplicationListenerMethodAdapter(beanName, type, method);
	}

这样就可以清楚的知道 @EventListener 内部的实现过程。

addApplicationListener

我们知道一个Event事件可以有多个Listener;一个Listener可以有多个Event,这里的Event主要是有继承关系,也就是说Listener可以监听一个父Event以及它所有的子Event。

  • 一个Listener监听多个Event

    SimpleApplicationEventMulticaster#multicastEvent
    @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)) {//找到对应的Listener
    			if (executor != null) { //处理异步事件
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
    				invokeListener(listener, event); //处理同步事件
    			}
    		}
    	}
    	//接着会调用这个方法
    	AbstractApplicationEventMulticaster#retrieveApplicationListeners
      private Collection<ApplicationListener<?>> retrieveApplicationListeners(
    			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
    		....
    		// Add programmatically registered listeners, including ones coming
    		// from ApplicationListenerDetector (singleton beans and inner beans).
    		for (ApplicationListener<?> listener : listeners) {
    			if (supportsEvent(listener, eventType, sourceType)) { //会去判断Listener是否支持Event的监听
    				if (retriever != null) {
    					retriever.applicationListeners.add(listener);
    				}
    				allListeners.add(listener);
    			}
    		}
        ....
      }
      //接着会调用
    	GenericApplicationListenerAdapter#supportsEventType
      @Override
    	@SuppressWarnings("unchecked")
    	public boolean supportsEventType(ResolvableType eventType) {
    		....
    		else {
    			return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType)); //这里会判断Listener<Event> 类的泛型类型是否是当前 multicast 的Event类型或者是否是其父类型
    		}
    	}
    
  • 一个Event多个Listener

    public abstract class AbstractApplicationEventMulticaster
          implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
       //一个ListenerCacheKey 对应一个 ListenerRetriever
       final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
      ....
    }
    // EventType 、SourceType 构建出来的对象,相当于一个Event对应一个ListenerCacheKey
    private static final class ListenerCacheKey implements Comparable<ListenerCacheKey> {
    		private final ResolvableType eventType;
    		@Nullable
    		private final Class<?> sourceType;
      	....
    }
    
    private class ListenerRetriever {
      	//包含了多个Listener
    		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
        ....
    }