2、监听器模式
2.1、监听器加入SpringBoot容器
@SpringBootApplicationpublic 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);
}
@Overridepublic 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));
}
}
@Overridepublic 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");
}
}
@SpringBootApplicationpublic 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