Spring Boot之事件原理剖析

在spring boot的启动的源码中,可以在很多个地方看到事件的应用。第三方插件与spring整合时也经常会借助事件来进行相关的初始化工作。事件的使用在启动中占有非常核心的地位。下面我们就透过源码来分析一下Spring Boot中是如何实现事件机制的。

看这个之前如果不了解事件设计模式的。可以先去看一下事件模式的原理!

实现的大致流程如下:
在这里插入图片描述
再来看一下在spring boot启动时是如何使用事件的

public ConfigurableApplicationContext run(String... args) {
		...
		//初始化事件调用工具类
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//发布spring boot正在启动事件
		listeners.starting();
		try {
			...
			//发布Spring boot应用已经启动完成事件
			listeners.started(context);
			...
		}
		catch (Throwable ex) {...}
		
		try {
		    //发布Spring Boot正在启动事件
			listeners.running(context);
		}catch (Throwable ex) { ... }
		
		return context;
	}
	/**
	* 使用SpringFactoriesLoader加载配置中的SpringApplicationRunListener的所有的实现类
	*/
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

可以看到,在应用启动的时候,会在启动不同阶段发布相应的事件。先看一下调用类SpringApplicationRunListeners 的源码实现逻辑:

class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

	void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}

	void running(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.running(context);
		}
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFailedListener(listener, context, exception);
		}
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		try {
			listener.failed(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message != null) ? message : "no error message";
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

}

可以看到这个类主要是管理SpringApplicationRunListener ,执行SpringApplicationRunListener中的逻辑。
在这里插入图片描述

由此可见,发布时间的核心逻辑在SpringApplicationRunListener的实现类中,在看一下它的实现类
在这里插入图片描述
在当前版本2.2.6.RELEASE中,只有一个实现类EventPublishingRunListener 。因此直接分析这个类的源码:

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    /**
    * Spring Boot 启动工具类
    */   
	private final SpringApplication application;

	private final String[] args;
    /**
     * 事件广播器 ,这才是发布事件的核心类
     */
	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		// 关键地方: 从SpringApplication获取其在构造时加载的ApplicationListener实例。添加到事件广播器中。
		for (ApplicationListener<?> listener : application.getListeners()) {
		    //将SpringApplication初始化加载的Listener实例全部存入SimpleApplicationEventMulticaster的defaultRetriever中
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

	@Override
	public int getOrder() {
		return 0;
	}

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}

	@Override
	public void started(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
	}

	@Override
	public void running(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
	}

	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all of the context's listeners instead
			if (context instanceof AbstractApplicationContext) {
				for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
						.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			this.initialMulticaster.multicastEvent(event);
		}
	}

	private static class LoggingErrorHandler implements ErrorHandler {

		private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);

		@Override
		public void handleError(Throwable throwable) {
			logger.warn("Error calling ApplicationEventListener", throwable);
		}

	}

}

注意:
1 EventPublishingRunListener中包了一个SpringApplication对象实例。这个对象在初始化的时候会使用SpringFactoriesLoader去加载配置好的ApplicationListener的实现类
2 EventPublishingRunListener中包了一个SimpleApplicationEventMulticaster(发布事件的最终实现,简称SAEM)对象,在SAEM初始化之后,会从SpringApplication实例中获取所有的ApplicationListener实现类的实例注入到SAEM中的defaultRetriever中

到这里就可以看到事件模式中的三个核心对象的实现:

  1. 事件广播者 SimpleApplicationEventMulticaster
  2. 事件 SpringApplicationEvent
  3. 事件监听器 ApplicationListener

下面来分析一下SimpleApplicationEventMulticaster :
在这里插入图片描述
发布事件的核心逻辑如下:

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	    //获取事件类型,根据这个去刚才添加的ApplicationListener集合中查询对应的实现类
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	    //获取线程池
		Executor executor = getTaskExecutor();
		//通过事件和事件类型来获取对应的ApplicationListener实例。
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		    //如果设置了线程池,就用线程池使用新线程执行当前监听器的逻辑
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
			    //如果没有设置线程池,就在当前线程中执行监听器的逻辑
				invokeListener(listener, event);
			}
		}
	}

	private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
		return ResolvableType.forInstance(event);
	}

再看事件SpringApplicationEvent的实现逻辑:
在这里插入图片描述
可以看到这里事件的定义和SpringApplicationRunListener接口中的方法的定义是惊人的相似。
也就是说,在spring boot应用启动的流程里会依次调用这7个事件:

  1. ApplicationStartingEvent
  2. ApplicationEnvironmentPreparedEvent
  3. ApplicationContextInitializedEvent .
  4. ApplicationPreparedEvent
  5. ApplicationStartedEvent
  6. ApplicationReadyEvent
  7. ApplicationFailedEvent

再来看一下监听器的实现,就以LoggingApplicationListener为例,如下
在这里插入图片描述
在GenericApplicationListener和SmartApplicationListener接口中有两个方法,将会在Event和Listener之间的匹配起到核心作用

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

	/**
	 * Determine whether this listener actually supports the given event type.
	 * 判断这个监听器是否支持给定的时间类型
	 * @param eventType the event type (never {@code null})
	 */
	boolean supportsEventType(ResolvableType eventType);

	/**
	 * Determine whether this listener actually supports the given source type.
	 * 判断这个事件是否支持给定的源类型
	 * <p>The default implementation always returns {@code true}.
	 * @param sourceType the source type, or {@code null} if no source
	 */
	default boolean supportsSourceType(@Nullable Class<?> sourceType) {
		return true;
	}

	/**
	 * Determine this listener's order in a set of listeners for the same event.
	 * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
	 */
	@Override
	default int getOrder() {
		return LOWEST_PRECEDENCE;
	}

}
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

	/**
	 * Determine whether this listener actually supports the given event type.
	 * @param eventType the event type (never {@code null})
	 */
	boolean supportsEventType(Class<? extends ApplicationEvent> eventType);

	/**
	 * Determine whether this listener actually supports the given source type.
	 * <p>The default implementation always returns {@code true}.
	 * @param sourceType the source type, or {@code null} if no source
	 */
	default boolean supportsSourceType(@Nullable Class<?> sourceType) {
		return true;
	}

	/**
	 * Determine this listener's order in a set of listeners for the same event.
	 * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
	 */
	@Override
	default int getOrder() {
		return LOWEST_PRECEDENCE;
	}

}

只有当这个两个方法同时返回true时,Event和Listener才匹配成功

这里问题来了,怎样通过SpringApplicationEvent实例去找到对应的ApplicationListener实例呢,它们之间关联逻辑是怎样实现的?

先看一下ApplicationContextInitializedEvent事件的结构(其他的事件与此类似):
在这里插入图片描述

可以看到只有一个构造函数,初始化时必须传入三个参数,分别是

  1. SpringApplication实例 ,会通过构造函数设置到顶级父类EventObject的source属性中
  2. ApplicationContext实例
  3. main方法启动传参args[]

在发布事件时是这样调用的:

 // 发布事件
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));

public void multicastEvent(ApplicationEvent event) {
	multicastEvent(event, resolveDefaultEventType(event));
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
	return ResolvableType.forInstance(event);
}

可以看到这里面又有一个重要对象ResolvableType ,它是通过SpringApplicationEvent事件实例去构造的 。这是一个包装类型,封装了Java对象原生的一些方法。

而根据事件实例匹配对应的事件监听器的逻辑都在AbstractApplicationEventMulticaster的getApplicationListeners(ApplicationEvent event, ResolvableType eventType)中实现。这里也加了内存缓存。就不在赘述了。还是直接撸AbstractApplicationEventMulticaster源码:

在根据ApplicationEvent匹配到对应的监听器实现集合时,会以ListenerCacheKey对象作为key,ListenerRetriever 为value存在本地的内存缓存中。

ListenerCacheKey 监听器缓存key
在这里插入图片描述

ListenerRetriever 监听器集合包装类。
在这里插入图片描述

    //默认的事件监听器集合包装类 ,
    //在SimpleApplicationEventMulticaster初始化后,会将SpringApplication对象中的所有的Listener实例存入到defaultRetriever中 
    //因此defaultRetriever包含了所有的监听器
	private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
    
    //监听器缓存,key=以事件类型和source构造的ListenerCacheKey对象,值为ListenerRetriever实例
	final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
	//同步锁
	private Object retrievalMutex = this.defaultRetriever;

/**
	 * Return a Collection of ApplicationListeners matching the given
	 * event type. Non-matching listeners get excluded early.
	 * @param event the event to be propagated. Allows for excluding
	 * non-matching listeners early, based on cached matching information.
	 * @param eventType the event type
	 * @return a Collection of ApplicationListeners
	 * @see org.springframework.context.ApplicationListener
	 */
	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
        //获取事件源,就是初始化事件中传递的SpringApplication对象实例。
		Object source = event.getSource();
		//sourceType = SpringApplication.class
		Class<?> sourceType = (source != null ? source.getClass() : null);
		//构建一个缓存key ,
		//参数eventType = SpringApplicationEvent事件的包装类ResolvableType实例
		//参数sourceType = SpringApplication.class
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

		// Quick check for existing entry on ConcurrentHashMap...
		//从缓存中获取对应事件的Listener集合,如果没有缓存则retriever = null
		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 ListenerRetriever
			//再以同步的方式去缓存中取
			synchronized (this.retrievalMutex) {
				retriever = this.retrieverCache.get(cacheKey);
				//如果缓存中有则还是使用缓存
				if (retriever != null) {
					return retriever.getApplicationListeners();
				}
				//缓存没有的话就新增一个空的ListenerRetriever对象用来存放想匹配的Listener实例
				retriever = new ListenerRetriever(true);
				//retrieveApplicationListeners方法是最终匹配事件和事件监听器的逻辑
				Collection<ApplicationListener<?>> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);
				//匹配到合适的监听器集合后,就存入缓存。
				this.retrieverCache.put(cacheKey, retriever);
				//返回结果
				return listeners;
			}
		}
		else {
			// No ListenerRetriever caching -> no synchronization necessary
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

下面来分析事件与事件监听器的匹配的核心逻辑代码retrieveApplicationListeners(ResolvableType,sourceType,ListenerRetriever )

/**
	 * Actually retrieve the application listeners for the given event and source type.
	 * @param eventType the event type
	 * @param sourceType the event source type
	 * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
	 * @return the pre-filtered list of application listeners for the given event and source type
	 */
	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

		List<ApplicationListener<?>> allListeners = new ArrayList<>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
		    //将所有的Listenner取出来存入Set集合中
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
		}

		// Add programmatically registered listeners, including ones coming
		// from ApplicationListenerDetector (singleton beans and inner beans).
		//遍历所有的监听器,通过时间类型来找到对应的监听器
		for (ApplicationListener<?> listener : listeners) {
		    // Determine whether the given listener supports the given event.
		    //事件和监听器的核心匹配逻辑,根据listener的内部定义来判断是否触发
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
				    //将匹配到的listener存入ListenerRetriever容器
					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.
		//如果listenerBeans不等空的就到spring的context中加载对应的类,这里初始化EventPublishingRunListener 的时候没有赋值,因此在此处的listenerBeans.isEmpty()=true
		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
				}
			}
		}

		AnnotationAwareOrderComparator.sort(allListeners);
		if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
			retriever.applicationListeners.clear();
			retriever.applicationListeners.addAll(allListeners);
		}
		return allListeners;
	}

从上面可以看到。事件匹配监听器时是通过supportsEvent(listener, eventType, sourceType)方法来实现。而这三个参数分别是:

  1. 监听器
  2. 事件类型
  3. 事件源类型
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
    //判断监听器是否是GenericApplicationListener的子类
    // 如果时,就强制转换为GenericApplicationListener 
    // 如果不是就构建一个GenericApplicationListener的适配器
	GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
			(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
	//调用listener的supportsEventType和supportsSourceType方法
	return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

综上,也就是说核心的匹配逻辑是在事件监听器中实现的 , 下面来看LoggingApplicationListener的具体实现:

public class LoggingApplicationListener implements GenericApplicationListener {

	private static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
			ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class,      ContextClosedEvent.class,ApplicationFailedEvent.class };

	private static final Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class };
	@Override
	public boolean supportsEventType(ResolvableType resolvableType) {
	    //判断事件类型是否是EVENT_TYPES定义的事件的本身或者子类
		return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
	}
	
	@Override
	public boolean supportsSourceType(Class<?> sourceType) {
	    //判断事件源是不是SOURCE_TYPES类定义的子类或者本身
		return isAssignableFrom(sourceType, SOURCE_TYPES);
	}
	
	private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
		if (type != null) {
			for (Class<?> supportedType : supportedTypes) {
				if (supportedType.isAssignableFrom(type)) {
					return true;
				}
			}
		}
		return false;
	}

}

可以看到,匹配的核心逻辑在EVENT_TYPES ,SOURCE_TYPES 的定义里面。到此spring的事件的核心逻辑面纱就彻底揭开了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值