Spring Boot - 扩展接口一览
众所周知,Spring Framework在 BeanFactory
的基础容器之上扩展为了ApplicationContext
上下文。 ApplicationContext
处理包含了BeanFactory
的全部基础功能之外,还额外提供了大量的扩展功能。
今天我们就来看看 扩展的 事件监听接口
我们都知道 实现事件监听机制至少四个组成部分:
在Spring中,事件监听机制主要实现是通过事件、事件监听器、事件发布者和事件广播器来实现。
public abstract class ApplicationContextEvent extends ApplicationEvent {/*** Create a new ContextStartedEvent.* @param source the {@code ApplicationContext} that the event is raised for* (must not be {@code null})*/public ApplicationContextEvent(ApplicationContext source) {super(source);}/*** Get the {@code ApplicationContext} that the event was raised for.*/public final ApplicationContext getApplicationContext() {return (ApplicationContext) getSource();}}
抽象父类ApplicationEvent
,它的子抽象类ApplicationContextEvent
包含有当前ApplicationContext
的引用,这样就可以确认每个事件是从哪一个Spring容器中发生的。
顶级接口ApplicationListener
,只有一个void onApplicationEvent(E event);
,当该监听器所监听的事件发生时,就会执行该方法
顶级接口ApplicationEventPublisher
,只有一个方法 void publishEvent(Object event);
,调用该方法就可以发生spring中的事件
spring中的事件核心控制器叫做事件广播器,两个作用
将事件监听器注册到广播器中
这样广播器就知道了每个事件监听器分别监听什么事件,且知道了每个事件对应哪些事件监听器在监听。
将事件广播给事件监听器
当有事件发生时,需要通过广播器来广播给所有的事件监听器,因为生产者只需要关心事件的生产,而不需要关心该事件都被哪些监听器消费。
ApplicationContext
被初始化或刷新时,该事件被发布。
也可以在ConfigurableApplicationContext
接口中使用 refresh()
方法来发生。
此处的初始化是指:所有的Bean
被成功装载,后处理Bean
被检测并激活,所有Singleton Bean
被预实例化,ApplicationContext
容器已就绪可用。
当使用 ConfigurableApplicationContext
接口中的 start()
方法启动 ApplicationContext
时,该事件被发布。
可以在接受到这个事件后重启任何停止的应用程序。
当使用 ConfigurableApplicationContext
接口中的 stop()
停止ApplicationContext
时,发布这个事件。
可以在接受到这个事件后做必要的清理的工作
当使用 ConfigurableApplicationContext
接口中的 close()
方法关闭 ApplicationContext
时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
这是一个 web-specific
事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet
的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件
@FunctionalInterface
public interface ApplicationListener extends EventListener {/*** Handle an application event.* @param event the event to respond to*/void onApplicationEvent(E event);/*** Create a new {@code ApplicationListener} for the given payload consumer.* @param consumer the event payload consumer* @param the type of the event payload* @return a corresponding {@code ApplicationListener} instance* @since 5.3* @see PayloadApplicationEvent*/static ApplicationListener> forPayload(Consumer consumer) {return event -> consumer.accept(event.getPayload());}}
ApplicationListener
可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。
首先看看Spring在初始化的时候,有两个核心步骤和事件监听器有关,一个是初始化事件广播器,一个是注册所有的事件监听器
org.springframework.context.support.AbstractApplicationContext#refresh
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Initialize event multicaster for this context.initApplicationEventMulticaster();// Check for listener beans and register them.registerListeners();}
/** Spring容器的事件广播器对象*/private ApplicationEventMulticaster applicationEventMulticaster;/** 事件广播器对应的beanName*/public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";/** 初始化事件广播器*/protected void initApplicationEventMulticaster() {//1.获取Spring容器BeanFactory对象ConfigurableListableBeanFactory beanFactory = getBeanFactory();//2.从BeanFactory获取事件广播器的bean,如果存在说明是用户自定义的事件广播器if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {//2.1.给容器的事件广播器赋值this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {//3.如果没有自定义的,则初始化默认的事件广播器SimpleApplicationEventMulticaster对象this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);//4.注册该beanbeanFactory.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() + "]");}}}
如果beanFactory
中存在用于自定义的就使用自定义的,如果没有自定义的就创建新的默认的事件广播器SimpleApplicationEventMulticaster
对象,然后赋值给applicationEventMulticaster
对象。
/** 注册事件监听器*/protected void registerListeners() {//1.遍历将通过编码方式创建的事件监听器加入到事件广播器中for (ApplicationListener> listener : getApplicationListeners()) {//2.获取到当前事件广播器,添加事件监听器getApplicationEventMulticaster().addApplicationListener(listener);}//3.从BeanFactory中获取所有实现了ApplicationListener接口的bean,遍历加入到事件广播器中String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}//3.获取需要提前发布的事件Set earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {//5.遍历将提前发布的事件广播出去getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
从容器中找到所有的事件监听器,然后调用事件广播器的addApplicationListener
方法将事件监听器添加到事件广播器中。
事件的发布是通过ApplicationEventPublisher
的实现类实现的publishEvent
方法实现的,ApplicationContext
就实现了该接口,所以使用Spring时就可以直接使用ApplicationContext
实例来调用publishEvent
方法来发布事件
/** 发布事件* @param event:事件对象* */@Overridepublic void publishEvent(Object event) {publishEvent(event, null);}/** 发布事件* @param event:事件对象* @param eventType:事件类型* */protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");/** 1.将发布的事件封装成ApplicationEvent对象(因为传入的参数是Object类型,有可能没有继承ApplicationEvent) */ApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent>) applicationEvent).getResolvableType();}}if (this.earlyApplicationEvents != null) {/** 2.1.如果需要提前发布的事件还没有发布完,则不是立即发布,而是将事件加入到待发布集合中*/this.earlyApplicationEvents.add(applicationEvent);}else {/** 2.2.获取当前的事件广播器,调用multicasterEvent方法广播事件*/getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}/** 3.如果当前applicationContext有父类,则再调用父类的publishEvent方法*/if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}
首先是将发布的事件转化成ApplicationEvent
对象,然后获取到事件广播器,调用事件广播器的multicastEvent
方法来广播事件,所以核心逻辑又回到了事件广播器那里
/** 广播事件* @param event:事件* @param eventType:事件类型* */@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));Executor executor = getTaskExecutor(); // (如果有Executor,则广播事件就是通过异步来处理的)/*** 1.根据事件和类型调用getApplicationListeners方法获取所有监听该事件的监听器* */for (ApplicationListener> listener : getApplicationListeners(event, type)) {if (executor != null) {/** 2. 异步遍历执行invokeListener方法来唤醒监听器处理事件 */executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}}
这里主要有两个核心步骤,
protected Collection> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {Object source = event.getSource();Class> sourceType = (source != null ? source.getClass() : null);ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);// Quick check for existing entry on ConcurrentHashMap...ListenerRetriever retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {return retriever.getApplicationListeners();}if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {// Fully synchronized building and caching of a ListenerRetrieversynchronized (this.retrievalMutex) {retriever = this.retrieverCache.get(cacheKey);if (retriever != null) {return retriever.getApplicationListeners();}retriever = new ListenerRetriever(true);Collection> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);this.retrieverCache.put(cacheKey, retriever);return listeners;}}else {// No ListenerRetriever caching -> no synchronization necessaryreturn retrieveApplicationListeners(eventType, sourceType, null);}}
核心方法是retrieveApplicationListeners(eventType, sourceType, retriever)
方法,源码如下:
private Collection> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class> sourceType, @Nullable ListenerRetriever retriever) {List> allListeners = new ArrayList<>();Set> listeners;Set listenerBeans;/** 初始化所有事件监听器,存入集合中*/synchronized (this.retrievalMutex) { listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}// Add programmatically registered listeners, including ones coming// 遍历所有监听器,调用supportsEvent判断是否监听该事件for (ApplicationListener> listener : listeners) {if (supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {retriever.applicationListeners.add(listener);} /** 如果监听器监听当前事件,则加入到监听器集合中*/allListeners.add(listener);}}// Add listeners by bean name, potentially overlapping with programmatically// registered listeners above - but here potentially with additional metadata.if (!listenerBeans.isEmpty()) {ConfigurableBeanFactory beanFactory = getBeanFactory();//for (String listenerBeanName : listenerBeans) {try {if (supportsEvent(beanFactory, listenerBeanName, eventType)) {ApplicationListener> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class);if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {if (beanFactory.isSingleton(listenerBeanName)) {retriever.applicationListeners.add(listener);}else {retriever.applicationListenerBeans.add(listenerBeanName);}}allListeners.add(listener);}}else {// Remove non-matching listeners that originally came from// ApplicationListenerDetector, possibly ruled out by additional// BeanDefinition metadata (e.g. factory method generics) above.Object listener = beanFactory.getSingleton(listenerBeanName);if (retriever != null) {retriever.applicationListeners.remove(listener);}allListeners.remove(listener);}}catch (NoSuchBeanDefinitionException ex) {// Singleton listener instance (without backing bean definition) disappeared -// probably in the middle of the destruction phase}}}/** 将所有监听器根据Order进行排序*/AnnotationAwareOrderComparator.sort(allListeners);if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {retriever.applicationListeners.clear();retriever.applicationListeners.addAll(allListeners);}return allListeners;}
核心步骤:
1:获取事件广播器中所有的事件监听器
2:遍历事件监听器,判断该监听器是否监听当前事件
3:将所有监听当前事件的监听器进行排序
第二步判断监听器是否监听事件的判断,主要是通过反射获取该监听器实现的接口泛型类,如果包含当前事件的类则表示监听,否则就表示不监听
protected void invokeListener(ApplicationListener> listener, ApplicationEvent event) {ErrorHandler errorHandler = getErrorHandler();if (errorHandler != null) {try {/** 调用doInvokeListener方法*/doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);}}else {/** 调用doInvokeListener方法*/doInvokeListener(listener, event);}}
继续
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {/** 直接调用ApplicationListener的onApplicationEvent(event)方法*/listener.onApplicationEvent(event);}catch (ClassCastException ex) {}}
直接调用监听器的onApplicationEvent
方法