SpringBoot之监听器解析

在这里插入图片描述

系统监听器
/**
 * Interface to be implemented by application event listeners.
 * Based on the standard {@code java.util.EventListener} interface
 * for the Observer design pattern.
 *
 * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
 * that it is interested in. When registered with a Spring ApplicationContext, events
 * will be filtered accordingly, with the listener getting invoked for matching event
 * objects only.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @param <E> the specific ApplicationEvent subclass to listen to
 * @see org.springframework.context.event.ApplicationEventMulticaster
 */
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

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

}
  1. ApplicationListener接口继承EventListener,EventListener 是一个标志接口,主要作用是声明这个接口的实现类都是系统监听器。
  2. @FunctionalInterface注解声明这个接口只有一个方法。
  3. ApplicationListener的泛型表示对什么事件感兴趣。
  4. onApplicationEvent()方法是相应事件发生时的回调方法。
系统广播器
/**
 * Interface to be implemented by objects that can manage a number of
 * {@link ApplicationListener} objects, and publish events to them.
 *  * <p>An {@link org.springframework.context.ApplicationEventPublisher}, typically
 * a Spring {@link org.springframework.context.ApplicationContext}, can use an
 * ApplicationEventMulticaster as a delegate for actually publishing events.
 *  * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 */
public interface ApplicationEventMulticaster {
	...
}

ApplicationEventMulticaster 主要是用来listeners的管理和事件的通知。

系统事件


在这里插入图片描述

监听器的实现(参考
  • 实现方式一
    1.实现ApplicationListener接口
    2.通过在 CLASSPATH/META-INF/spring.factories 中添加 org.springframework.context.ApplicationListener = [ 监听器全类名 ]
  • 实现方式二
    1.实现ApplicationListener接口
    2.在启动类中,使用 ConfigurableApplicationContext.addApplicationListener() 方法注册。
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
// 注册 MyApplicationListener 事件监听器
context.addApplicationListener(new MyApplicationListener());
  • 实现方式三
    1.实现ApplicationListener接口
    2.在 Springboot 核心配置文件 application.properties 中增加 context.listener.classes = [ 监听器全类名 ]。该 context.listener.classes 配置项在 DelegatingApplicationListener 类的属性常量中指定。
  • 实现方式四
    1.使用 @Component 等注解将事件监听器纳入到 Spring 容器中管理。
  • 实现方式五
    1.使用 @EventListener 注解自动生成并注册事件监听器。
  • 实现方式六
    1.实现SmartApplicationListener接口
    2.重写supportsEventType()方法,表明自己关注的事件
    3.通过上面前三种的方法注入到框架
    在这里插入图片描述
监听器的加载

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

我们可以看到监听器是在SpringApplication的构造方法中完成注册的,注册的原理跟系统初始化器的原理大致相同,都是通过SpringFactoriesLoader 加载然后注册的。
进入getSpringFactoriesInstances方法(间接进入)

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//重点:调用了SpringFactoriesLoader.loadFactoryNames(type, classLoader)方法
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)方法 (这个方法最主要的是调用loadSpringFactories()这个方法,下面直接分析这个方法)

	/**
	* 使用指定的classloader扫描classpath上所有的JAR包中的文件META-INF/spring.factories,加载其中的多值
	* 工厂属性定义,使用多值Map的形式返回
	**/
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	    //查询缓存
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			// 扫描classpath上所有JAR中的文件META-INF/spring.factories
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				// 找到的每个META-INF/spring.factories文件都是一个Properties文件,将其内容
				// 加载到一个 Properties 对象然后处理其中的每个属性
				URL url = urls.nextElement();
				// url 对应某个 META-INF/spring.factories 配置文件资源
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				// properties 来自 url 对应某个 META-INF/spring.factories 配置文件资源
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					// 获取工厂类名称(接口或者抽象类的全限定名)
					String factoryClassName = ((String) entry.getKey()).trim();
					// 将逗号分割的属性值逐个取出,然后放到多值Map结果result中去。
					for (String factoryName : StringUtils.commaDelimitedListToStringArray(
						(String) entry.getValue())) {
						// 放到 result 中 :
						// key 使用 factoryClassName
						// value 可能有多值, 使用 factoryName
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			// 放到缓存中,key 使用 classLoader
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

通过loadSpringFactories()获得所有的工厂属性,然后通过getOrDefault()过滤获得key为
org.springframework.context.ApplicationListener的值并返回。然后通过createSpringFactoriesInstances()方法反射创建。

	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				// 加载类
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				// 获取默认的构造方法
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				// 使用默认的构造方法实例化类
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

系统初始化器加载的大致流程

监听事件触发机制

进入SpringApplication.run()方法

	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();

Spring 在这里设计得很精巧。使用的是观察者模式,可以无需对启动时的其它业务 bean 的配置关心,只需要正常启动创建 Spring 应用上下文环境。。将 SpringApplicationRunListeners 作为信息发布者 , SpringApplicationRunListener 作为信息订阅者。
(下面的SpringApplicationRunListener分析主要参考)
进入getRunListeners()方法

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		//getSpringFactoriesInstances()因为之前已经加载过将类路径下所有的META-INF/spring.factories的文件中的属性进行加载
		//并缓存到SpringFactoriesLoader的缓存cache中,这里直接从缓存中获取,并实例化返回
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

总的来说,getRunListeners做了什么事呢?就是获取SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),并封装进SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说的再简单点,getRunListeners就是准备好了运行时监听器EventPublishingRunListener。下面我们分析一下EventPublishingRunListener。

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

EventPublishingRunListener的构造方法中,构造了一个SimpleApplicationEventMulticaster对象,并将SpringApplication的listeners中的全部listener赋值到SimpleApplicationEventMulticaster对象的属性defaultRetriever(类型是ListenerRetriever)的applicationListeners集合中。

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

跟着代码进入到了这两个方法

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}
	@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)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

resolveDefaultEventType(event)的作用获取当前事件对应的类型,该结果用于getApplicationListeners(event, type)方法,返回与给定事件类型匹配的ApplicationListeners集合,非匹配的侦听器会被提前排除;允许根据缓存的匹配结果来返回。
进入getApplicationListeners(event, type))方法

/**
	 * 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) {

		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 ListenerRetriever
			synchronized (this.retrievalMutex) {
				retriever = this.retrieverCache.get(cacheKey);
				if (retriever != null) {
					return retriever.getApplicationListeners();
				}
				retriever = new ListenerRetriever(true);
				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);
		}
	}
  1. 缓存中是否有匹配的结果,有则返回
  2. 若缓存中没有匹配的结果,则从this.defaultRetriever.applicationListeners中过滤,这个this表示的EventPublishingRunListener对象的属性initialMulticaster
  3. 过滤过程,遍历defaultRetriever.applicationListeners集合,从中找出ApplicationStartingEvent匹配的listener,具体的匹配规则需要看各个listener的supportsEventType方法(有两个重载的方法)
  4. 将过滤的结果于键值对的形式缓存到retrieverCache,key为ListenerCacheKey类型的对象,它通过传入的事件生成。
  5. 将过滤出的结果返回回去。
executor.execute(() -> invokeListener(listener, event));

如果设置了线程池,通过线程池调用监听器的onApplicationEvent方法。没有的话直接调用。

发布了6 篇原创文章 · 获赞 0 · 访问量 275

猜你喜欢

转载自blog.csdn.net/weixin_43960292/article/details/105358554