监听器
EventPublishingRunListener
今天我们来讲监听器,话不多说先从SpringApplication#run
方法中的getRunListeners
讲起
java
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
// ... 以下代码省略
}
进入getRunListeners
方法
arduino
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
如果看过SpringFactoriesLoader
的话应该就很熟悉这段代码了,这里的getSpringFactoriesInstances
就是通过这个工厂加载类来加载实体类,贴上代码,具体不再详细说明,可以看我的上一篇文章,注意这个方法传入的第一个参数是SpringApplicationRunListener.class
typescript
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
根据第一个参数,也就是说我们最后会在spring.factories
中找到对应的实例也就是EventPublishingRunListener
ini
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
先来看下EventPublishingRunListener
是做什么的
从源代码中可以看到EventPublishingRunListener
实现了SpringApplicationRunListener
这个接口,该接口定义了几个方法用于监听SpringApplication
启动和运行或者叫生命周期的不同阶段。所以EventPublishingRunListener
通过事件发布的方式通知注册的监听器应用程序的不同阶段,比如启动、环境准备、应用程序上下文准备、应用程序启动、运行以及失败等
php
/**
* Listener for the {@link SpringApplication} {@code run} method.
* {@link SpringApplicationRunListener}s are loaded via the {@link SpringFactoriesLoader}
* and should declare a public constructor that accepts a {@link SpringApplication}
* instance and a {@code String[]} of arguments. A new
* {@link SpringApplicationRunListener} instance will be created for each run.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
*/
public interface SpringApplicationRunListener {
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
在首次启动run方法时立即调用。 可用于非常早的初始化
*/
void starting();
/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
在准备ApplicationContext之后,创建好ApplicationContext之前调用
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
在创建和准备ApplicationContext之后,但在加载源之前调用
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
在ApplicationContext加载完之后但是在其刷新之前调用
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* The context has been refreshed and the application has started but
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
* ApplicationRunners} have not been called.
* @param context the application context.
* @since 2.0.0
上下文已刷新,应用程序已启动,但CommandLineRunner 和ApplicationRunner 尚未被调用
*/
void started(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
* @param context the application context.
* @since 2.0.0
在刷新应用程序上下文并已调用所有CommandLineRunner和ApplicationRunner后,在run方法完成之前立即调用
*/
void running(ConfigurableApplicationContext context);
/**
* Called when a failure occurs when running the application.
* @param context the application context or {@code null} if a failure occurred before
* the context was created
* @param exception the failure
* @since 2.0.0
在应用程序启动或运行期间出现异常时调用。可以用于处理应用程序失败的情况。
*/
void failed(ConfigurableApplicationContext context, Throwable exception);
}
事实上,在createSpringFactoriesInstances
中还会调用构造方法从而创建实例,从上面我们知道这边找到了EventPublishingRunListener
,因此会调用该类的构造方法
typescript
@SuppressWarnings("unchecked")
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;
}
我们来看一下它的构造方法做了那些事情
kotlin
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 这边的application.getListeners() 在 new SpringApplication(primarySources).run(args)时保存了listeners,所以可以拿到注册的监听器
for (ApplicationListener<?> listener : application.getListeners()) {
// 存储在SimpleApplicationEventMulticaster的内部类中是一个set(继承了抽象类AbstractApplicationEventMulticaster)
this.initialMulticaster.addApplicationListener(listener);
}
}
该方法将加载到的监听器放入了容器中,先想一下这里的application.getListeners()
从何而来?下面这段代码还记得吗,没错在SpringApplication
构建时就加载了包括系统初始化器以及监听器,从而将这些监听器存入了SimpleApplicationEventMulticaster
kotlin
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
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();
}
接着我们来看看SimpleApplicationEventMulticaster
又是什么
ApplicationEventMulticaster
scala
/**
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
*
* <p>Multicasts all events to all registered listeners, leaving it up to
* the listeners to ignore events that they are not interested in.
* Listeners will usually perform corresponding {@code instanceof}
* checks on the passed-in event object.
*
* <p>By default, all listeners are invoked in the calling thread.
* This allows the danger of a rogue listener blocking the entire application,
* but adds minimal overhead. Specify an alternative task executor to have
* listeners executed in different threads, for example from a thread pool.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
* @see #setTaskExecutor
*/
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
}
首先SimpleApplicationEventMulticaster
继承自AbstractApplicationEventMulticaster
kotlin
/**
* Abstract implementation of the {@link ApplicationEventMulticaster} interface,
* providing the basic listener registration facility.
*
* <p>Doesn't permit multiple instances of the same listener by default,
* as it keeps listeners in a linked Set. The collection class used to hold
* ApplicationListener objects can be overridden through the "collectionClass"
* bean property.
*
* <p>Implementing ApplicationEventMulticaster's actual {@link #multicastEvent} method
* is left to subclasses. {@link SimpleApplicationEventMulticaster} simply multicasts
* all events to all registered listeners, invoking them in the calling thread.
* Alternative implementations could be more sophisticated in those respects.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 1.2.3
* @see #getApplicationListeners(ApplicationEvent, ResolvableType)
* @see SimpleApplicationEventMulticaster
*/
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
...
/**
* Helper class that encapsulates a specific set of target listeners,
* allowing for efficient retrieval of pre-filtered listeners.
* <p>An instance of this helper gets cached per event type and source type.
该类主要用于帮助 ApplicationEventMulticaster 的实现类管理监听器(listeners)和它们的订阅关系
*/
private class ListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(
this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listener)) {
allListeners.add(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}
}
而AbstractApplicationEventMulticaster
又实现了ApplicationEventMulticaster
,该类提供了一些基本的、通用的方法和属性,如对 ApplicationListener
的管理(ListenerRetriever
)等。
java
/**
* Interface to be implemented by objects that can manage a number of
* {@link ApplicationListener} objects, and publish events to them.
这是一个可以管理多个 ApplicationListener 对象并向它们发布事件的接口。
这意味着它负责将事件传递给所有注册的监听器
*
* <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 {
/**
* Add a listener to be notified of all events.
* @param listener the listener to add
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Add a listener bean to be notified of all events.
* @param listenerBeanName the name of the listener bean to add
*/
void addApplicationListenerBean(String listenerBeanName);
/**
* Remove a listener from the notification list.
* @param listener the listener to remove
*/
void removeApplicationListener(ApplicationListener<?> listener);
/**
* Remove a listener bean from the notification list.
* @param listenerBeanName the name of the listener bean to add
*/
void removeApplicationListenerBean(String listenerBeanName);
/**
* Remove all listeners registered with this multicaster.
* <p>After a remove call, the multicaster will perform no action
* on event notification until new listeners are being registered.
*/
void removeAllListeners();
/**
* Multicast the given application event to appropriate listeners.
* <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
* if possible as it provides a better support for generics-based events.
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);
/**
* 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 null)
* @since 4.2
*/
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
ApplicationEventMulticaster
它允许对象管理一组 ApplicationListener
对象,并将事件发布给这些监听器
接着我们来看它是如何管理对象和发布事件的
回到代码EventPublishingRunListener#starting
,代码流程为
SpringApplication#run -> listeners.starting() -> SpringApplicationRunListeners#starting -> listener.starting() -> EventPublishingRunListener#starting
该方法广播了一个事件,名为ApplicationStartingEvent
,也就是multicastEvent
方法的第一个参数
java
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
看一下SimpleApplicationEventMulticaster
的multicastEvent
方法
less
@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));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
这两个方法需要传入ApplicationEvent
事件
scala
/**
* Class to be extended by all application events. Abstract as it
* doesn't make sense for generic events to be published directly.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
看一下该类的子类都有哪些
有没有觉得在哪里见过,没错这些子类事件正好对应了SpringApplicationRunListener
定义的不同阶段
回到SimpleApplicationEventMulticaster#multicastEvent
方法
less
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取事件对应的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// 执行监听器方法
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
整体来说该方法就做了两件事。首先根据事件类型获取该事件对应监听器,获取到对应监听器之后调用监听器的onApplicationEvent
方法完成相应的动作
流程
最后来看下整体流程
- 方法启动时首先进入构造方法,构造方法会通过spring.factores文件找到ApplicationListener所有的实例并存储
- 构造器执行完毕进入run方法,同样的,在getRunListeners中会获取SpringApplicationRunListener的实现,也就是EventPublishingRunListener。还有调用EventPublishingRunListener的构造方法,保存上一步存储的监听器到内部容器中(AbstractApplicationEventMulticaster#ListenerRetriever)
- listeners.starting(),进入EventPublishingRunListener的starting方法并调用SimpleApplicationEventMulticaster的multicastEvent,这里会传入事件类型ApplicationStartingEvent
- multicastEvent方法会找到事件对应的监听器并调用监听器的onApplicationEvent
流程图如下(图片出自:github.com/coderbruis/...)