Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,372 @@
### 事件监听器触发机制解析



#### 以SpringBoot Staring事件具例子

- SpringContext#run方法中的,listeners.staring()方法

```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();
try {
```



- SpringApplicationRunListeners#starting() 内部方法

```java
public void starting() {
// 调用 SpringApplicationRunListenser#staring() 方法
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
```



- SpringApplicationRunListener方法,定义了框架各个阶段的事件监听方法

```java
/**
* 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
* @since 1.0.0
*/
public interface SpringApplicationRunListener {

/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void starting();

/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
*/
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
*/
void contextPrepared(ConfigurableApplicationContext context);

/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
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
*/
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
*/
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);

}
```



- SpringApplicationRunListener#starting() 方法,通过 SimpleApplicationEventMulticaster 广播器发送 ApplicationStartingEvent 事件

```java
/**
* {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
* <p>
* Uses an internal {@link ApplicationEventMulticaster} for the events that are fired
* before the context is actually refreshed.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Artsiom Yudovin
* @since 1.0.0
*/
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

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();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}

@Override
public void starting() {
// 通过广播器,发送ApplicationStaringEvent事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

```



- SimpleApplicationEventMulticaster#multicastEvent() 广播器发送方法

```java
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

@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();
// 通过AbstractApplicationEventMulticaster#getApplicationListeners() 方法获得对该事件感兴趣的监听器列表
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
```



- AbstractApplicationEventMulticaster#getApplicationListeners() 方法,获得对该事件感兴趣的监听器列表

```java
/**
* 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
// 避免其它线程操作ListenersCache缓存
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
// 双重检测锁
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 通过AbstractApplicationEventMulicaster#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);
}
}
```



- 如果 this.retrieverCache 缓存获取不到 监听器列表,就从AbstractApplicationEventMulticaster#retrieveApplicationListeners()中获取

```java
/**
* 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;
// 通过互斥锁初始化Set<ApplicationListener>对象
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
/**
获取所有事件监听器
在 spring.factories 中定义的实践监听器
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
*/
for (ApplicationListener<?> listener : listeners) {
// 判断是否对该事件感兴趣
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
// 感兴趣就加入到集合当中
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, 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);
}
}
}
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;
}
```



- 通过AbstractApplicationEventMuliticaster#supportEvent() 方法,判断该事件监听器,是否对该事件感兴趣?

```java
/**
* Determine whether the given listener supports the given event.
* <p>The default implementation detects the {@link SmartApplicationListener}
* and {@link GenericApplicationListener} interfaces. In case of a standard
* {@link ApplicationListener}, a {@link GenericApplicationListenerAdapter}
* will be used to introspect the generically declared type of the target listener.
* @param listener the target listener to check
* @param eventType the event type to check against
* @param sourceType the source type to check against
* @return whether the given listener should be included in the candidates
* for the given event type
*/
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

// 判断当前事件监听器是否是GenericApplicationListerner接口类的实现类,如果不是的话,就做个委派,方便获取该事件监听器感兴趣事件
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
// 判断当前监听器是否感兴趣该事件
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
```





#### 获取监听器列表逻辑

<img src="https://tva1.sinaimg.cn/large/008i3skNly1gunchq5avkj618e0u0q5l02.jpg" alt="image-20210920200242597" align="left" width="700" />

- 通过AbstractApplicationEventMulticaster#getApplicationListeners()方法获取感兴趣事件监听器列表
- 判断当前SpringBoot缓存中是否存在该事件感兴趣的监听器列表
- 如果没有,调用通过AbstractApplicationEventMulicaster#retrieveApplicationListener()方法,获取所有事件监听器列表
- 遍历所有事件监听器列表
- 通过AbstractApplicationEventMuliticaster#supportsEvent() 方法查找出对该事件感兴趣的事件监听器
- 将感兴趣的事件监听器列表加入SpirngBoot缓存中,并返回给事件触发器



#### AbstractApplicationEventMuliticaster#supportEvent() 事件监听器匹配器触发条件

<img src="/Users/huangyan110110114/Library/Application Support/typora-user-images/image-20210920201046825.png" alt="image-20210920201046825" align="left" width="850" />
2 changes: 1 addition & 1 deletion springboot-source-code-analysis/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ipman.source.code.analysis.springboot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.example.springboot.source.code.analysis.event.RainListener;
import com.example.springboot.source.code.analysis.event.WeatherRunListener;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

Expand Down