2、监听器模式

编程

2.1、监听器加入SpringBoot容器

@SpringBootApplication

public class SpringbootApplication {

public static void main(String[] args) {

SpringApplication.run(SpringbootApplication.class, args);

}

}

// 走到SpringApplication的构造函数,这边代码第一节也分析过

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();

// 获取spring.factories中配置的初始化器,这边获取时也将监听器等也获取了,并放入缓存中

setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));

// 这边步骤同获取初始化器步骤,也是通过SpringFactoriesLoader读取,由于已经获取过,直接从缓存取

// 下图是SpringBoot默认配置的监听器

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

this.mainApplicationClass = deduceMainApplicationClass();

}

2.2、发布事件

SpringBoot在容器的关键节点会发布一些事件,上图是SpringBoot的事件发布顺序

1) 框架启动时会发出starting事件,框架一启动就发出

2) 接着会在环境准备好之后发出一个environmentPrepared事件,代表SpringBoot已经把系统属性以及我们指定的一些属性加载完毕

3) 接着发出一个contextInitialized事件,表示SpringBoot上下文已经准备好,是在加载任何Bean定义之前发布

4) 接着发送一个prepared事件,表示SpringBoot应用上下文已经创建完成,但是bean还没有完全加载完成

5) 发送started事件,表示SpringBoot已经将单例的bean完成了,但是还没有调用ApplicationRunner和CommandLineRunner两个扩展接口,

这两个接口后面分析

6) 发送ready事件,在上述两个扩展接口调用之后,发布该事件

7) SpringBoot容器出现失败,发送failed事件

// SpringApplicationRunListener中定义了发布上述事件的方法,通过该接口将发布事件的方法暴露出来,从而隐藏了具体实现

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);

}

// SpringBoot在容器的关键节点会发布一些事件

// run方法时SpringBoot的核心方法,删除部分无关代码

public ConfigurableApplicationContext run(String... args) {

// 步骤1)

SpringApplicationRunListeners listeners = getRunListeners(args);

// 步骤2) 框架已启动就发布starting事件

listeners.starting();

try {

context = createApplicationContext();

prepareContext(context, environment, listeners, applicationArguments,printedBanner);

refreshContext(context);

afterRefresh(context, applicationArguments);

return context;

}

}

2.2.1、步骤1

// 步骤1) 

SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {

// types是待会获取EventPublishingRunListener构造函数的参数

Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };

return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class,

types, this, args));

}

// 这边代码第一节已经分析过了,通过SpringFactoriesLoader获取指定Type的实现类,并实例化

private <t> Collection<t> getSpringFactoriesInstances(Class<t> type,

Class<?>[] parameterTypes, Object... args) {

ClassLoader classLoader = getClassLoader();

// 通过SpringFactoriesLoader获取指定Type的实现类,这边获取SpringApplicationRunListener的

// 实现类是EventPublishingRunListener,它也是SpringBoot暴露出来的用于事件发布的类

Set<string> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

// 将EventPublishingRunListener实例化

List<t> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

AnnotationAwareOrderComparator.sort(instances);

return instances;

}

// 上述实例化EventPublishingRunListener时,会通过反射调用其构造函数

public EventPublishingRunListener(SpringApplication application, String[] args) {

this.application = application;

this.args = args;

this.initialMulticaster = new SimpleApplicationEventMulticaster();

// application.getListeners获取的就是通过SpringFactoriesLoader获取的,在步骤2.1)节已经分析

for (ApplicationListener<?> listener : application.getListeners()) {

this.initialMulticaster.addApplicationListener(listener);

}

}

public void addApplicationListener(ApplicationListener<!--?--> listener) {

synchronized (this.retrievalMutex) {

// Explicitly remove target for a proxy, if registered already,

// in order to avoid double invocations of the same listener.

Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);

if (singletonTarget instanceof ApplicationListener) {

this.defaultRetriever.applicationListeners.remove(singletonTarget);

}

// 加入到this.defaultRetriever.applicationListeners,后面会用到

this.defaultRetriever.applicationListeners.add(listener);

this.retrieverCache.clear();

}

}

2.2.2、发布事件

// 步骤2) 框架已启动就发布starting事件

listeners.starting();

public void starting() {

for (SpringApplicationRunListener listener : this.listeners) {

// 这边的listener就是EventPublishingRunListener,通过它来发布事件

listener.starting();

}

}

@Override

public void starting() {

// 发布容器启动事件

this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));

}

@Override

public void multicastEvent(ApplicationEvent event) {

// 参数2是解析事件类型

multicastEvent(event, resolveDefaultEventType(event));

}

@Override

public void multicastEvent(final ApplicationEvent event,

@Nullable ResolvableType eventType) {

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

// 没有配置,默认为null

Executor executor = getTaskExecutor();

// 步骤a) 获取哪些监听器对这个事件感兴趣

for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {

if (executor != null) {

executor.execute(() -> invokeListener(listener, event));

}

else {

// 步骤b) 走这边

invokeListener(listener, event);

}

}

}

// 步骤a) 获取哪些监听器对这个事件感兴趣

protected Collection<applicationlistener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {

// 获取事件源,这里是SpringApplication

Object source = event.getSource();

Class<?> sourceType = (source != null ? source.getClass() : null);

// 根据事件类型和事件源构造缓存key

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();

}

// beanClassLoader为null,走这个分支

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);

// 获取listeners并放入retriever,下面分析这个步骤

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);

}

}

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

// 这边在2.2.1、步骤1分析到了,就是SpringBoot默认配置的一些监听器

listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);

listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);

}

// 依此遍历每个监听器,判断该监听器是否对该事件感兴趣

for (ApplicationListener<?> listener : listeners) {

// 关键方法,下面分析这里

if (supportsEvent(listener, eventType, sourceType)) {

if (retriever != null) {

retriever.applicationListeners.add(listener);

}

allListeners.add(listener);

}

}

if (!listenerBeans.isEmpty()) {

// 默认为空,删掉这边分析

}

// 对listeners排序

AnnotationAwareOrderComparator.sort(allListeners);

if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {

retriever.applicationListeners.clear();

retriever.applicationListeners.addAll(allListeners);

}

return allListeners;

}

protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, 

@Nullable Class<?> sourceType) {

// 判断是否是GenericApplicationListener,如果不是包装为GenericApplicationListenerAdapter

GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?

(GenericApplicationListener) listener :

new GenericApplicationListenerAdapter(listener));

// 正式判断是否对该事件感兴趣,分为两步supportsEventType和supportsSourceType

return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));

}

// 包装时做了两件事

public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {

Assert.notNull(delegate, "Delegate listener must not be null");

// 获取监听器类型

this.delegate = (ApplicationListener<applicationevent>) delegate;

// 获取该监听器感兴趣的事件类型

this.declaredEventType = resolveDeclaredEventType(this.delegate);

}

@Override

public boolean supportsEventType(ResolvableType eventType) {

// 判断是否是SmartApplicationListener,如果是,它有自己独有的supportsEventType方法,调用该方法

// 判断是否支持

if (this.delegate instanceof SmartApplicationListener) {

Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();

return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));

}

else {

// 如果不是,直接根据eventType判断是否是declaredEventType子类

return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));

}

}

@Override

public boolean supportsSourceType(@Nullable Class<?> sourceType) {

// 如果不属于SmartApplicationListener,直接返回true

// 如果是,那么判断supportsSourceType

return !(this.delegate instanceof SmartApplicationListener) ||

((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);

}

// 步骤b) 走这边

invokeListener(listener, event);

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {

ErrorHandler errorHandler = getErrorHandler();

if (errorHandler != null) {

try {

doInvokeListener(listener, event);

}

catch (Throwable err) {

errorHandler.handleError(err);

}

}

else {

// 走这边

doInvokeListener(listener, event);

}

}

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {

try {

// 调用各个listener的onApplicationEvent方法

listener.onApplicationEvent(event);

}

}

2.3、自定义监听器

2.3.1、方式1

@Order(1)

public class FirstListener implements ApplicationListener<applicationstartedevent> {

@Override

public void onApplicationEvent(ApplicationStartedEvent event) {

System.out.println("hello first");

}

}

// 在resources目录下的META-INF/spring.factories文件中配置,监听器配置同初始化器

org.springframework.context.ApplicationListener=com.lwh.springboot.listener.FirstListener

2.3.2、方式2

@Order(2)

public class SecondListener implements ApplicationListener<applicationstartedevent> {

@Override

public void onApplicationEvent(ApplicationStartedEvent event) {

System.out.println("hello second");

}

}

@SpringBootApplication

public class SpringbootApplication {

public static void main(String[] args) {

//测试SecondInitializer时用这种启动方式,手动添加

SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);

springApplication.addListeners(new SecondListener());

springApplication.run(args);

}

}

2.3.3、方式3

@Order(3)

public class ThirdListener implements ApplicationListener<applicationstartedevent> {

@Override

public void onApplicationEvent(ApplicationStartedEvent event) {

System.out.println("hello third");

}

}

// 在application.properties中配置

context.listener.classes=com.lwh.springboot.listener.ThirdListener

// 在application.properties中配置被加入SpringBoot的原理分析

其中有一个DelegatingApplicationListener,这个listener会获取application.properties中的context.listener.classes属性,

将其加入listeners集合中

2.3.4、方式4

@Order(4)

public class FourthListener implements SmartApplicationListener {

@Override

public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {

return ApplicationStartedEvent.class.isAssignableFrom(eventType) ||

ApplicationPreparedEvent.class.isAssignableFrom(eventType);

}

@Override

public void onApplicationEvent(ApplicationEvent event) {

System.out.println("hello fourth");

}

}

添加方式同前面三种

2.4、面试题

1、介绍下监听器模式

2、SpringBoot关于监听器相关的实现类有哪些?

3、SpringBoot框架有哪些事件以及他们的顺序?

4、介绍下监听事件的触发机制

5、如何自定义实现系统监听器及注意事项

6、实现ApplicationListener接口与SmartApplicationListener接口区别

ApplicationListener只能指定一个感兴趣的事件,而SmartApplicationListener定义了supportsEventType方法,可以指定多个感兴趣的事件,

也定义了supportsSourceType方法,可以指定事件源

以上是 2、监听器模式 的全部内容, 来源链接: utcz.com/z/513536.html

回到顶部