概述
什么是事件/监听
监听/事件机制其实是由Spring实现的一种事件/监听器模式,可视为观察者模式。在Spring应用上下文ApplicationContext广播事件之后,监听器监听到后会做出相应事件的处理。
相应在SpringBoot中,在充分使用到Spring的ApplicationListener的同时也实现了SpringBoot的监听器SpringApplicationRunListener,实现了自己的事件/监听机制。本文具体介绍Spring下的事件/监听机制,SpringApplicationRunListener就不再展开了。
ApplicationListener 属于 org.springframework.context包下。
SpringApplicationRunListener属于 org.springframework.boot包下。
SpringBoot下的监听器
大家都知道SpringBoot是由SpringApplication.run()方法启动的,在SpringApplication的构造函数中,可以看到调用了一个名为setListeners的函数,该函数会将META-INF/spring.factories下所有的监听器加入到listeners属性中。
private List<ApplicationListener<?>> listeners;
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();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 将META-INF/spring.factories下所有的监听器加入到listeners属性中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>();
this.listeners.addAll(listeners);
}
这个监听器列表会在org.springframework.context.support.AbstractApplicationContext#registerListeners 方法中被遍历添加进org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever#applicationListeners 属性中。
protected void registerListeners() {
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
...
}
函数调用栈如下图所示。
"main@1" prio=5 tid=0x1 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:836)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
- locked <0xf23> (a java.lang.Object)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:137)
- locked <0xf5b> (a java.util.concurrent.atomic.AtomicBoolean)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:197)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:104)
at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:70)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:74)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:338)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:297)
at com.hsw.alibabanacosdiscoveryserver.AlibabaNacosDiscoveryServerApplication.main(ServerApplication.java:30)
那么绕这么大一圈把所有的监听器添加到这个org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever#applicationListeners 属性到底有什么用呢?别急,我们先来看看事件广播的地方在哪。Spring和SpingBoot的所有事件发布者都是 SimpleApplicationEventMulticaster,在org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType) 方法中,正是 invokeListener 这个函数调用了org.springframework.context.ApplicationListener#onApplicationEvent 函数,完成了对事件的处理。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取到所有的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 使用给定的监听器调用给定的事件
invokeListener(listener, event);
}
}
}
那么聪明的读者自然应该可以看出,在invokeListener之前, 自然是通过 getApplicationListeners 函数获取到了所有的事件监听器。在Spring Framework 3.0之前的ApplicationListener 只能监听所有的事件,除非使用instanceof方法进行筛选。而在3.0之后,ApplicationListener 支持了ApplicationEvent的泛型监听, onApplicationEvent 可以选择监听指定的事件,而不需要instanceof来进行过滤。具体代码就不占用博客空间,读者可自行查看ApplicationListener的源码。
自定义一个监听器和一个事件
分析到这里,相信读者已经对springboot下的事件/监听机制有了大致的了解。接下来我们来看看如何自定义一个监听器和事件,又怎么样来实现事件的监听和广播呢?
/**
* 自定义事件
* @author hsw
* @Date 22:47 2019/7/11
*/
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(Object source) {
super(source);
}
}
/**
* 自定义监听器
* @author hsw
* @Date 22:47 2019/7/11
*/
@Slf4j
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
log.info("MyApplicationEvent.source: " + event.getSource());
}
}
@SpringBootApplication
@Slf4j
public class ServerApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(ServerApplication.class);
springApplication.setBannerMode(Banner.Mode.OFF);
ConfigurableApplicationContext context = springApplication.run(args);
// 添加事件监听器
context.addApplicationListener(new MyApplicationListener());
// 事件的广播
context.publishEvent(new MyApplicationEvent("this is a customize applicationEvent"));
}
}
可以看到代码都十分简单。
1、自定义了一个名为 MyApplicationEvent 的事件
2、自定义了一个名为 MyApplicationListener 的监听器
3、在springboot启动后获取到spring上下文后将监听器加入到监听器列表中
4、完成对自定义事件的广播
控制台输出日志 :
[
main] c.h.a.event.MyApplicationListener
: MyApplicationEvent.source: this is a customize applicationEvent
事件的异步处理
那么现在已经成功的完成了自定义事件/监听器,但是通过日志可以看到,监听器对事件的处理是由main线程来进行处理的,也就是说事件的处理是同步,那么如何能让事件的处理成为异步的呢?回到上面的 multicastEvent 方法中:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取到所有的监听器
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 使用给定的监听器调用给定的事件
invokeListener(listener, event);
}
}
}
可以看到在事件处理之前,spring做了一个判断,通过 getTaskExecutor 函数去获取了一个taskExecutor属性的线程池,也就是说只要在事件处理之前为这个属性set上值,那么spring就会通过异步线程池的方式来对事件进行处理!而在org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster 函数初始化 SimpleApplicationEventMulticaster 的时候,会查看beanFactory中是否有名为 applicationEventMulticaster 的bean存在,若有则直接使用该bean。那么只需定义一个名为 applicationEventMulticaster 的bean即可完成事件的异步处理!
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
加入自定义的 SimpleApplicationEventMulticaster
@Bean("applicationEventMulticaster")
public ApplicationEventMulticaster getApplicationEventMulticaster () {
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
simpleApplicationEventMulticaster.setTaskExecutor(Executors.newFixedThreadPool(1, r -> new Thread(r, "myThread")));
return simpleApplicationEventMulticaster;
}
再次执行main函数,获取到如下日志:
[
myThread] c.h.a.event.MyApplicationListener
: MyApplicationEvent.source: this is a customize applicationEvent
成功使用自定义线程池处理自定义事件!
本文SpringBoot版本为2.0.9
参考:SpringBoot编程思想(小马哥)
最后
以上就是自信灰狼为你收集整理的深入分析SpringBoot下的事件/监听机制以及实现所有事件的异步处理什么是事件/监听SpringBoot下的监听器自定义一个监听器和一个事件事件的异步处理的全部内容,希望文章能够帮你解决深入分析SpringBoot下的事件/监听机制以及实现所有事件的异步处理什么是事件/监听SpringBoot下的监听器自定义一个监听器和一个事件事件的异步处理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复