我是靠谱客的博主 舒心发卡,这篇文章主要介绍Spring-Boot和Spring的监听器模式,现在分享给大家,希望可以做个参考。

最近阅读SpringBoot的源码,发现一个奇怪的现象:项目中有两处地方具有发布事件功能,一个是SpringApplicationRunListener接口;另一个是ApplicationEventPublisher接口的publishEvent方法,ApplicationContext接口实现了该接口。标准监听器模式应该只会有一个地方可以发布事件,这里为什么会有两个呢?

先说结论。

经过仔细分析,发现SpringApplicationRunListener接口是属于SpringBoot包下的,该接口用于发布SpringBoot相关流程的事件;而ApplicationEventPublisher接口属于org.springframework.context包,用于ApplicationContext在refresh的流程中调用,refresh是应用上下文启动的核心方法。

也就是说,SpringApplicationRunListener接口用于监听SpringBoot的启动流程,而ApplicationEventPublisher用于监听Spring应用上下文的启动流程。

那么为什么要使用新的客户端监听SpringBoot的流程呢?

原因是SpringBoot项目是Spring项目的扩展,所以不能够让Spring的代码和SpringBoot的代码产生耦合,为了监听SpringBoot本身的启动流程,于是引入了SpringApplicationRunListener接口。另一个原因是SpringBoot启动过程中,需要用到监听器的地方还没有对ApplicationContext完成refresh,所以也没法使用ApplicationContext的publishEvent功能。

上面就是两个地方会调用到同一个SimpleApplicationEventMulticaster的原因(当然两个地方调用的SimpleApplicationEventMulticaster实例是不同的,以便于分隔监听器)。

1.SpringApplicationRunListener

public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void finished(ConfigurableApplicationContext context, Throwable exception);
}

该接口唯一的实现类EventPublishingRunListener,调用的SimpleApplicationEventMulticaster进行事件广播,在SpringApplication启动的上面五个流程中,发布不同的事件。

2.AbstractApplicationContext

该类是应用上下文的抽象类,里面的publishEvent方法和监听器有关,这里就不贴代码了,调用的是AbstractApplicationContext的属性applicationEventMulticaster,该属性通过initApplicationEventMulticaster方法进行初始化,实际也是初始化了SimpleApplicationEventMulticaster的实例。下面分析一下广播器相关类。

3.SimpleApplicationEventMulticaster

该实现类继承自AbstractApplicationEventMulticaster,而AbstractApplicationEventMulticaster抽象类实现了ApplicationEventMulticaster接口。

AbstractApplicationEventMulticaster抽象类定义了广播器的规范实现,并且定义了ListenerRetriever内部类,ListenerRetriever将获取监听器的功能独立出来,可以通过多个方式获取监听器,这里是通过applicationListeners属性保存的监听器和applicationListenerBeans保存的监听器beanName来共同获取到监听器。

private class ListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<String>();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<ApplicationListener<?>>(
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
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
}
SimpleApplicationEventMulticaster扩展了多线程调用监听器的功能,但如果没有从外部调用setTaskExecutor方法设置线程池,那么默认还是使用的当前线程。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
private Executor taskExecutor;
private ErrorHandler errorHandler;
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
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(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}

4.事件及事件类型

所有实现ApplicationListener接口的监听器,都只能获取到实现ApplicationEvent抽象类的事件,该抽象类保存的信息只有事件的创建时间。另外ApplicationEvent抽象类继承了EventObject普通类,EventObject是java.util包下的,只有一个source属性,表示事件来源。

实现GenericApplicationListener接口的监听器,可以添加是否支持相应ResolvableType

和来源类型的判断。

ResolvableType可以通过ApplicationEvent进行构造,把对应ApplicationEvent的实例放在ResolvableType的resolved属性当中。


private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
public static ResolvableType forInstance(Object instance) {
Assert.notNull(instance, "Instance must not be null");
if (instance instanceof ResolvableTypeProvider) {
ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType();
if (type != null) {
return type;
}
}
return ResolvableType.forClass(instance.getClass());
}
public static ResolvableType forClass(Class<?> clazz) {
return new ResolvableType(clazz);
}
private ResolvableType(Class<?> clazz) {
this.resolved = (clazz != null ? clazz : Object.class);
this.type = this.resolved;
this.typeProvider = null;
this.variableResolver = null;
this.componentType = null;
this.hash = null;
}

最后

以上就是舒心发卡最近收集整理的关于Spring-Boot和Spring的监听器模式的全部内容,更多相关Spring-Boot和Spring内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部