系统监听器
/**
* 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);
}
- ApplicationListener接口继承EventListener,EventListener 是一个标志接口,主要作用是声明这个接口的实现类都是系统监听器。
- @FunctionalInterface注解声明这个接口只有一个方法。
- ApplicationListener的泛型表示对什么事件感兴趣。
- 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);
}
}
- 缓存中是否有匹配的结果,有则返回
- 若缓存中没有匹配的结果,则从this.defaultRetriever.applicationListeners中过滤,这个this表示的EventPublishingRunListener对象的属性initialMulticaster
- 过滤过程,遍历defaultRetriever.applicationListeners集合,从中找出ApplicationStartingEvent匹配的listener,具体的匹配规则需要看各个listener的supportsEventType方法(有两个重载的方法)
- 将过滤的结果于键值对的形式缓存到retrieverCache,key为ListenerCacheKey类型的对象,它通过传入的事件生成。
- 将过滤出的结果返回回去。
executor.execute(() -> invokeListener(listener, event));
如果设置了线程池,通过线程池调用监听器的onApplicationEvent方法。没有的话直接调用。