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过程中,从抽象类AbstractApplicationContextrefresh方法开始,去除注释和日志,我们来看看源码

@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();
		}
	}
}

  • 这里我们只关心两个方法initApplicationEventMulticasterregisterListeners

  • 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);
		}
	}
}

添加监听器到applicationListenersapplicationListenerBeans集合

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最终还是调用的实现类AbstractApplicationContextpublishEvent方法

@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

可以看到对应的线程名称已经发生了改变。

posted @ 2024-11-18 17:02  雩娄的木子  阅读(52)  评论(0编辑  收藏  举报