Spring监听器之@EventListener
Spring监听器
监听器可以在使用过程时监听某些事件的发生,然后对这些事件做出响应处理。监听器对应用场景很多,用户的每一个操作都可以被定义为一个事件,通过监听器就能对某些业务场景中的事件进行监听。
Spring中提供了ApplicationListener监听事件,本文会从应用出发讲解Spring的监听器,并逐步深入到源码之中。
一、两种使用最经典的使用方式
下面我着重介绍两种最常见的使用方式
-
实现接口
-
使用注解
1.1、首先定义事件类
package com.guang.listener.event;
import com.guang.listener.entity.MyEntity;
import org.springframework.context.ApplicationEvent;
/**
* @Title: MyEntityEvent
* @Author liguang
* @Package com.guang.listener.event
* @Date 2024/11/15 10:36
* @description:
*/
public class MyEntityEvent extends ApplicationEvent {
public MyEntityEvent(MyEntity myEntity) {
super(myEntity);
}
}
可以看到构造参数中
这里两个参数,一个是时间戳,记录一下发送事件的时间;另外一个是source,表示发送事件的源,代表的是事件所表示的真实含义。
1.2、发送事件所表示的业务实体
package com.guang.listener.entity;
import lombok.*;
import java.io.Serializable;
/**
* @Title: MyEntity
* @Author liguang
* @Package com.guang.listener.entity
* @Date 2024/11/15 10:34
* @description: 监听事件实体
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyEntity implements Serializable {
private static final long serialVersionUID = 7099057708183571937L;
/**
* 监听人名称信息
*/
private String name;
/**
* 监听人ID信息
*/
private Integer id;
/**
* 监听内容信息
*/
private String content;
}
1.3、第一种方式:实现接口监听器
package com.guang.listener.demo2;
import com.guang.listener.entity.MyEntity;
import com.guang.listener.event.MyEntityEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* @Title: MyEntityListener
* @Author liguang
* @Package com.guang.listener.listener
* @Date 2024/11/15 10:37
* @description: 我的实体监听器
*/
@Component
@Slf4j
public class MyEntityDemo2Listener implements ApplicationListener<MyEntityEvent> {
@Override
public void onApplicationEvent(MyEntityEvent myEntityEvent) {
log.info("监听到了event事件");
Object source = myEntityEvent.getSource();
MyEntity myEntity = (MyEntity) source;
log.info("监听到的实体信息为:{}",myEntity);
}
}
1.4、第二种方式:实现注解监听器
package com.guang.listener.demo1;
import com.guang.listener.entity.MyEntity;
import com.guang.listener.event.MyEntityEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* @Title: MyEntityListener
* @Author liguang
* @Package com.guang.listener.listener
* @Date 2024/11/15 10:37
* @description: 我的实体监听器
*/
@Component
@Slf4j
public class MyEntityDemo1Listener {
// 默认是同步事件,断点打在这里,默认不会继续向下继续执行
@EventListener(classes = MyEntityEvent.class)
public void onApplicationEvent(MyEntityEvent event) {
log.info("监听到了event事件");
Object source = event.getSource();
MyEntity myEntity = (MyEntity) source;
log.info("监听到的实体信息为:{}",myEntity);
}
}
1.5、测试
package com.guang.listener.controller;
import com.guang.listener.entity.MyEntity;
import com.guang.listener.event.MyEntityEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Title: ListenerController
* @Author liguang
* @Package com.guang.listener.controller
* @Date 2024/11/15 13:30
* @description:
*/
@RestController
public class ListenerController {
@Resource
private ApplicationContext applicationContext;
@GetMapping(path = "demo1")
public ResponseEntity<String> demo1() {
applicationContext.publishEvent(new MyEntityEvent(new MyEntity("demo1", 1, "demo1")));
return ResponseEntity.ok("demo1");
}
}
1.6、结果
2024-11-15 13:39:45.457 INFO 14932 --- [nio-8080-exec-1] c.g.l.demo2.MyEntityDemo2Listener : 监听到了event事件
2024-11-15 13:39:45.458 INFO 14932 --- [nio-8080-exec-1] c.g.l.demo2.MyEntityDemo2Listener : 监听到的实体信息为:MyEntity(name=demo1, id=1, content=demo1)
2024-11-15 13:39:48.510 INFO 14932 --- [nio-8080-exec-1] c.g.l.demo1.MyEntityDemo1Listener : 监听到了event事件
2024-11-15 13:39:48.510 INFO 14932 --- [nio-8080-exec-1] c.g.l.demo1.MyEntityDemo1Listener : 监听到的实体信息为:MyEntity(name=demo1, id=1, content=demo1)
可以看到两种监听器都可以使用起来了。
二、接口监听器添加原理
监听器到底是怎么实现的呢?下面来分析一下对应的源码。
2.1、接口方式注册监听器
首先看一下实现接口方式的监听原理,这个是在创建applicationContext过程中,从抽象类AbstractApplicationContext的refresh方法开始,去除注释和日志,我们来看看源码
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
// 初始化一个广播器,之后注册监听器和发布事件都基于该广播器执行
initApplicationEventMulticaster();
onRefresh();
// 注册监听器到广播器中
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
-
这里我们只关心两个方法initApplicationEventMulticaster和registerListeners
-
initApplicationEventMulticaster();
protected void initApplicationEventMulticaster() {
// 获取bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断是否存在applicationEventMulticaster这个bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 如果存在则实例化这个bean并保存到applicationEventMulticaster
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
// 否则创建一个广播器并注册单例到bean工厂
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
- registerListeners();
protected void registerListeners() {
// 获取得到手动从容器中添加的一种获取得到监听器的一种方式
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 从bean工厂获取所有实现了ApplicationListener接口的bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 预处理方法(prepareRefresh)之后,注册监听器方法(registerListeners)之前,发布的广播/事件(publishEvent)的都会缓存在这里进行统一发布,相当于创建应用上下文时的延迟广播
// multicastEvent方法具体实现放在发布过程详解
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
添加监听器到applicationListeners和applicationListenerBeans集合
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// 获取代理对象
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
// 避免重复添加监听器,主要防止代理类和被代理类同时处理一个事件
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
// 由于在发布事件后会找到所有监听他的监听器并且缓存下来,所以当添加新的监听器时需要清空缓存,这样下次发布事件才能让新添加的监听器有机会处理事件
this.retrieverCache.clear();
}
}
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
至此监听器已经全部注册完毕,都是基于initApplicationEventMulticaster方法生成的广播器进行注册,同时可以看到发布也是基于这个广播器发布的(multicastEvent方法)
2.2、发布(publishEvent)方法
上面的只是注册监听器,下面来发布事件之后的流程。
接口ApplicationEventPublisher最终还是调用的实现类AbstractApplicationContext的publishEvent方法
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
继续跟踪
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 判断事件源是否实现了ApplicationEvent接口并进行转化
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
// 如果没有也要封装成ApplicationEvent事件
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 在初始化应用上下文预处理方法(prepareRefresh)之后,注册监听器方法(registerListeners)之前,这期间的发布全部进行延迟发布,交由registerListeners方法统一发布
// 此时earlyApplicationEvents为null
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 获取广播器并发布事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 通过父上下文发布事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
开始发布事件
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 包装事件源,可以方便解析事件源的泛型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取任务执行(默认为空)
Executor executor = getTaskExecutor();
// 通过事件源和事件类型获取感知的监听器后遍历发布
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 如果有设置任务执行则使用任务执行发布
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 如果没有设置任务执行则直接发布
invokeListener(listener, event);
}
}
}
看一下如果通过事件源和时间类型获取得到监听器进行发布的
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
// 获取事件的源
Object source = event.getSource();
// 事件源的类型
Class<?> sourceType = (source != null ? source.getClass() : null);
// 一个简单类,当做map的key使用,用以区分不同的事件类型并设置缓存
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 尝试从缓存获取
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
// 如果缓存不为空则返回监听器列表
if (retriever != null) {
return retriever.getApplicationListeners();
}
// 判断类是否可以缓存的
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);
// 通过事件源查找符合的监听器
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever);
// 设置缓存
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// 通过事件源查找符合的监听器
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
最终是通过retrieveApplicationListeners方法进行监听器查找的
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) {
// 获取前面注册监听器方法(registerListeners)注册的监听器
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);
}
}
// 解析通过实现ApplicationListener接口的监听器
if (!listenerBeans.isEmpty()) {
// 获取bean工厂
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
// 判断是否符合监听器
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
// 通过bean工厂获取监听器
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
// 如果不存在结果集中并且符合需要感知的监听器
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
// 如果需要缓存
if (retriever != null) {
// 如果是单例,则添加监听器到缓存,否则添加beanName缓存
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
// 添加到查找到的监听器中
allListeners.add(listener);
}
}
else {
// 删除不符合感知的监听器需要移除对应的缓存和监听器结果
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
// 对监听器排序,如果存在@Order注解
AnnotationAwareOrderComparator.sort(allListeners);
// 如果applicationListenerBeans为空说明监听器全部在allListeners里,则清空applicationListeners重新添加即可
// applicationListenerBeans为空说明没有非单例bean
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
// 反正最终查找到的监听器
return allListeners;
}
至此所有匹配的监听器已经找到,至于如何判断是否符合监听器的各位看官有兴趣可以自行了解,最后我们看看发布方法invokeListener
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 {
// 调用实现类的onApplicationEvent方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
- 到这里所有方法解析就结束了
总结
通过阅读源码,我们知道除了基础的应用,spring还为我们提供了哪些功能
1、自己编写一个类实现ApplicationEventMulticaster接口代替默认的SimpleApplicationEventMulticaster广播器
2、通过调用setTaskExecutor(@Nullable Executor taskExecutor)方法制定广播器的执行计划
3、通过调用setErrorHandler(@Nullable ErrorHandler errorHandler)方法异常处理方案
4、在监听器上添加@Order(int)注解制定监听器执行顺序
5、期待留言补充。。。
三、注解式监听器原理
3.1、注册原理
查看SpringBoot的源码,找到下面的代码,因为我是Tomcat环境,这里创建的ApplicationContext是org.springframework.bootweb.servlet.context.AnnotationConfigServletWebServerApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
他的构造方法如下:
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
进到AnnotatedBeanDefinitionReader
里面
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
再进到AnnotationConfigUtils
的方法里面,省略了一部分代码,可以看到他注册了一个EventListenerMethodProcessor
类到工厂了。这是一个BeanFactory
的后置处理器。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
......
.....
......
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
......
......
return beanDefs;
}
查看这个BeanFactory的后置处理器EventListenerMethodProcessor,下面方法,他会遍历所有bean,找到其中带有@EventListener的方法,将它包装成ApplicationListenerMethodAdapter(本质上也是一个ApplicationListener),注册到工厂里,这样就成功注册到Spring的监听系统里了。
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
!targetType.getName().startsWith("java") &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
由方法生成Listener
的逻辑由EventListenerFactory
完成的,这又分为两种,一种是普通的@EventLintener
另一种是@TransactionalEventListener
,是由两个工厂处理的。
上面介绍了@EventListener的原理,其实上面方法里还有一个@TransactionalEventListener注解,其实原理是一模一样的,只是这个监听者可以选择在事务完成后才会被执行,事务执行失败就不会被执行。
这两个注解的逻辑是一模一样的,并且@TransactionalEventListener本身就被标记有@EventListener,
只是最后生成监听器时所用的工厂不一样而已。分别看下:
DefaultEventListenerFactory和
package org.springframework.context.event;
import java.lang.reflect.Method;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
private int order = LOWEST_PRECEDENCE;
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public boolean supportsMethod(Method method) {
return true;
}
@Override
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new ApplicationListenerMethodAdapter(beanName, type, method);
}
}
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {
private int order = 50;
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public boolean supportsMethod(Method method) {
return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
}
@Override
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new TransactionalApplicationListenerMethodAdapter(beanName, type, method);
}
}
3.2、发布(publishEvent)方法
这里和接口监听器发布方法也差不多,但是有点区别。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> 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()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
因为这里不再试接口了,而是对应的注解了。所以这里选择我们的ApplicationListenerMethodAdapter,查看一下对应的处理方法。
@Override
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
继续跟踪:
public void processEvent(ApplicationEvent event) {
// 确定参数
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
// 目标方法调用
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
直接查看对应的方法:
protected Object doInvoke(Object... args) {
// 找到对应的bean,这里直接通过对应的beanName进行调用的!
// 如果不是被代理的bean,那么这里bean的名称就是对应的listener名称;如果是代理对象,那么这里的beanName将会是被代理
// 对象的名称!这个很好理解,请参考FactoryBean中获取得到target对象的名称
Object bean = getTargetBean();
// Detect package-protected NullBean instance through equals(null) check
if (bean.equals(null)) {
return null;
}
ReflectionUtils.makeAccessible(this.method);
try {
// 直接通过对象进行调用
return this.method.invoke(bean, args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(this.method, bean, args);
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (InvocationTargetException ex) {
// Throw underlying exception
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else {
String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);
throw new UndeclaredThrowableException(targetException, msg);
}
}
}
直接通过反射调用即可!!!
但是这里需要注意的:这里的反射调用的对象是target,如果被代理的情况下就是代理对象。所以经常使用到@Async注解是在该方法执行之前调用的。
断点一下可以看到
所以真实的调用如果是@Async,那么将会最终发生调用代理中的异步线程方法中去。
3.3、@EventListener+@Async结合使用
package com.guang.listener.configuration;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.*;
/**
* @author Hollis
*/
@Configuration
@EnableAsync
public class TestListenerConfig {
@Bean("testListenExecutor")
public Executor orderListenExecutor() {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("testListener-%d").build();
ExecutorService executorService = new ThreadPoolExecutor(10, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
return executorService;
}
}
对应的事件
package com.guang.listener.demo4;
import com.guang.listener.entity.MyEntity;
import com.guang.listener.event.MyEntityEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
/**
* @Title: MyEntityListener
* @Author liguang
* @Package com.guang.listener.listener
* @Date 2024/11/15 10:37
* @description: 使用接口来对事件进行监听
*/
@Component
@Slf4j
public class MyEntityDemo4Listener {
// 默认是同步事件,断点打在这里,默认不会继续向下继续执行
@EventListener
@Async(value = "testListenExecutor")
public void onApplicationEvent(MyEntityEvent event) {
log.info("监听到了event事件");
Object source = event.getSource();
MyEntity myEntity = (MyEntity) source;
log.info("监听到的实体信息为:{}",myEntity);
log.info("打印当前线程名称:{}",Thread.currentThread().getName());
}
}
在发布事件之后,可以看到对应的线程处理
2024-11-18 16:56:16.143 INFO 11044 --- [ testListener-0] c.g.l.demo4.MyEntityDemo4Listener : 监听到的实体信息为:MyEntity(name=demo1, id=1, content=demo1)
2024-11-18 16:56:16.144 INFO 11044 --- [ testListener-0] c.g.l.demo4.MyEntityDemo4Listener : 打印当前线程名称:testListener-0
可以看到对应的线程名称已经发生了改变。