srpingboot web - 启动 监听器
Posted Sniper_ZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了srpingboot web - 启动 监听器相关的知识,希望对你有一定的参考价值。
接上一篇
一. getRunListeners()
在run() 方法中调用了 getRunListeners(args) 方法, 先看一下这个方法干了什么
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
加载配置 spring.factories 中的配置,
# Run Listeners org.springframework.boot.SpringApplicationRunListener=\\ org.springframework.boot.context.event.EventPublishingRunListener
然后创建配置中的 EventPublishingRunListener , 封装到 SpringApplicationRunListeners 类中的 this.listeners 属性中.
1. 创建 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); } }
1. 这里创建了一个多播器: SimpleApplicationEventMulticaster
2. 将容器中10个监听器放入多播器中.
上一篇提到过, 容器中加载了10个监听器, 放在 this.listeners 属性中.
这里的顺序与配置的读取顺序不同, 是经过排序过的.
addApplicationListener()
@Override 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.add(listener); this.retrieverCache.clear(); } }
ListenerRetriever 是 AbstractApplicationEventMulticaster 的一个内部类. 所以监听器是放在 一个内部类的 applicationListeners 属性中:
public final Set<ApplicationListener<?>> applicationListeners;
二. listeners.starting()
public void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } }
此处的 this.listeners 中的 this -> SpringApplicationRunListeners .
所以调用的是 EventPublishingRunListener的starting() 方法.
//EventPublishingRunListener.java @Override public void starting() {
//创建Application的启动事件, 并进行多波 this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); }
看一下 multicastEvent 方法:
//SimpleApplicationEventMulticaster.java @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));
// getApplicationListeners 会对监听器进行过滤 for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//获取线程池, 暂时为null Executor executor = getTaskExecutor(); if (executor != null) {
//异步发送事件 executor.execute(() -> invokeListener(listener, event)); } else {
//同步发送事件 invokeListener(listener, event); } } }
getApplicationListeners()
protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); }
1. 判断监听器是否为 GenericApplicationListener 类型
|-> 如果是, 则调用其 supportsEventType() 和 supportsSourceType() , 且同时满足, 才可以. 否则会被过滤掉
|-> 如果不是, 则 使用GenericApplicationListenerAdapter 进行适配转换, 然后 调用上面两个方法, 同时满足, 才可以. 否则会被过滤掉
满足条件的有4个监听器:
此处看一下 LoggingApplicationListener 的两个方法执行:
1. supportsEventType()
private static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class, ApplicationFailedEvent.class }; @Override public boolean supportsEventType(ResolvableType resolvableType) { return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES); } @Override public boolean supportsSourceType(Class<?> sourceType) { return isAssignableFrom(sourceType, SOURCE_TYPES); } private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) { if (type != null) { for (Class<?> supportedType : supportedTypes) { if (supportedType.isAssignableFrom(type)) { return true; } } } return false; }
可以看到, 这里他支持5中类型, 其中正好就有当前发布的 ApplicationStartingEvent 事件.
2. supportsSourceType()
private static final Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class }; @Override public boolean supportsSourceType(Class<?> sourceType) {
//这里调用的还是上面的那个方法, 只是传入参数不同 return isAssignableFrom(sourceType, SOURCE_TYPES); }
invokeListener()
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
//不管 errorhandler 是否为null, 都会调用 doInvokeListener 方法 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(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) { // Possibly a lambda-defined listener which we could not resolve the generic event type for // -> let\'s suppress the exception and just log a debug message. Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } }
这里就是调用 监听器的 onApplicationEvent 方法, 并传入要多波的事件.
这里仍然来看 LoggingApplicationListener 的 onApplicationEvent 方法:
@Override public void onApplicationEvent(ApplicationEvent event) {
//Application启动 if (event instanceof ApplicationStartingEvent) { onApplicationStartingEvent((ApplicationStartingEvent) event); }
//环境准备完成 else if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent( (ApplicationEnvironmentPreparedEvent) event); }
//Application 准备完 else if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent((ApplicationPreparedEvent) event); }
//容器关闭 else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event) .getApplicationContext().getParent() == null) { onContextClosedEvent(); }
//Application启动失败 else if (event instanceof ApplicationFailedEvent) { onApplicationFailedEvent(); } }
不同的事件进来, 执行不同的方法.
以上是关于srpingboot web - 启动 监听器的主要内容,如果未能解决你的问题,请参考以下文章