一、组成部分
spring的事件监听有三个部分组成,事件(ApplicationEvent)、监听器(ApplicationListener)和事件发布操作。
二、具体实现
事件
事件对象就是一个简单的po实体类
1、需要实现接口ApplicationEvent,
2、构造方法需要设置super
3、我们可以另外拓展一些子类来区分不同事件的实体
public abstract class BaseEvent<T> extends ApplicationEvent { protected T eventData; protected String topic; /** * Create a new {@code ApplicationEvent}. * * @param source 事件产生处所在类的对象 * @param eventData 表示在事件传播过程中,需要传输的对象,随意设置数据类型 * @param topic topic */ public BaseEvent(Object source, T eventData,String topic) { super(source); this.eventData = eventData; this.topic = topic; } public T getEventData() { return eventData; } public String getTopic(){ return topic; } }
子类举例
public class SimpleEvent<T> extends BaseEvent { //需要传输的事件主题 private String topic; //用于接受事件的返回值 private List result; public SimpleEvent(Object source) { super(source); } public SimpleEvent(Object source, T eventData) { super(source, eventData); } public SimpleEvent(Object source, T eventData, String topic) { super(source,eventData); this.topic = topic; } public void setResult(List<String> result) { this.result = result; } public String getTopic() { return topic; } public List<String> getResult() { return result; } }
发布者
发布者很简单,需要注意三点
1、注入到spring容器中
2、引入应用上下文让我们的事件发布到流程中
3、调用 publishEvent 时传入事件po对象
@Component public class SimpleEventPublisher<T> { @Resource ApplicationContext applicationContext; public void publish(T msg) { applicationContext.publishEvent(new SimpleEvent<>(this, msg)); } public void publish(T msg, String topic) { applicationContext.publishEvent(new SimpleEvent<>(this, msg, topic)); } public List<String> publishAndReceive(T msg, String topic) { SimpleEvent<T> simpleEvent = new SimpleEvent<>(this, msg, topic); applicationContext.publishEvent(simpleEvent); return simpleEvent.getResult(); } }
监听者
两种实现方式
1、@EventListener 注解实现
@EventListener 所在的监听方法是根据参数列表的EventPo类型来进行监听的,正常来讲对不同的事件po监听需要对应不同的监听方法。
@EventListener 也有两个参数 classes(事件po类) 和 condition(满足条件走此方法) ,这两个参数默认不用填写
如果多个监听方法的入参事件po列表一致,就会重复监听同一个事件。
2、类实现
实现 ApplicationListener<事件PO> 并重写方法就行
@Component public class SimpleEventListener { public static final String eventBindTopic ="event#setNeedBindInfo"; public static final String eventBindBackTopic ="event#setBindBackTopic"; @Order(0) @EventListener public void doMsg(SimpleEvent<String> simpleEvent){ if (simpleEvent.getTopic().equals(eventBindTopic)){ UserEventDto eventData = (UserEventDto) simpleEvent.getEventData(); log.info("普通监听器-》接受到事件[{}],数据体【{}】",simpleEvent.getTopic(),eventData); }else if (simpleEvent.getTopic().equals("event#setBindBackTopic")){ // 由于传入的事件与前面发布的事件内存地址指向的是同一个,这里可以设置值用于返回 simpleEvent.setResult(Collections.singletonList("这里是返回参数pong")); log.info("有返回值监听器-》 topic【{}】,全数据体【{}】",simpleEvent.getTopic(), simpleEvent); }else { log.info("无匹配监听器 topic【{}】,数据体【{}】", simpleEvent.getTopic(),simpleEvent.getEventData()); } } }
三、原理探寻
一、解析@EventListener前的准备工作
1.1 EventListenerFactory和EventListenerMethodProcessor的注入
EventListenerFactory 是把 @EventListener 标注的方法变成 ApplicationListener 的关键,其是在容器最初期(refresh方法发生前)就放到容器中去
EventListenerMethodProcessor 是 @EventListener 的解析类,他是一个 SmartInitializingSingleton 和 BeanFactoryPostProcessor
ApplicationListener 是把 @EventListener 包装了一层
初始化的时候先判断,没有就注入 EventListenerMethodProcessor 和 DefaultEventListenerFactory 到容器中
源码如下
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, Object source) { //获取对象 DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); //org.springframework.context.event.internalEventListenerProcessor //@EventListener注解处理器 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)); } //org.springframework.context.event.internalEventListenerProcessor //内部管理的EventListenerFactory的bean名称 if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
1.2 EventListenerMethodProcessor和EventListenerFactory关系的建立
EventListenerMethodProcessor会在容器启动时被注入到容器中,他是一个BeanFactoryPostProcessor
EventListenerMethodProcessor和EventListenerFactory关系的建立,发生在其方法postProcessBeanFactory中
EventListenerFactory的实例化时机只比BeanFactoryPostProcessor晚,比BeanPostProcessor实例化早
EventListenerMethodProcessor源码:
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { @Nullable private List<EventListenerFactory> eventListenerFactories; //初始化eventListenerFactories @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { this.beanFactory = beanFactory; //获取容器中所有的EventListenerFactory,并把他们实例化 Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false); List<EventListenerFactory> factories = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(factories); //将EventListenerFactory储存到缓存eventListenerFactories中,便于后来使用 this.eventListenerFactories = factories; } }
二、开始解析@EventListener
EventListenerMethodProcessor是一个SmartInitializingSingleton,所以他会在所以bean实例化后,执行其afterSingletonsInstantiated方法
注意:只有单例的SmartInitializingSingleton,才会执行其afterSingletonsInstantiated方法
2.1 基本流程
获取容器中所有的类,把用 @Component 标注的类上所有的 @EventListener 方法用 EventListenerFactory 解析成一个 ApplicationListener
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { @Override public void afterSingletonsInstantiated() { ConfigurableListableBeanFactory beanFactory = this.beanFactory; Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); // 这里厉害了,用Object.class 是拿出容器里面所有的Bean定义~~~ 一个一个的检查 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) { if (logger.isDebugEnabled()) { logger.debug("", 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 { // 真正处理这个Bean里面的方法们。。。 processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("", ex); } } } } } private void processBean(final String beanName, final Class<?> targetType) { //类上有@Component注解 if (!this.nonAnnotatedClasses.contains(targetType) &&!targetType.getName().startsWith("java") &&!isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { //获取类中用@EventListener标注方法的信息 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); } } //如果annotatedMethods为空,那代表类中没有用@EventListener标注的方法 if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { logger.trace("" + targetType.getName()); } } else { // 类中存在用@EventListener标注的方法 ConfigurableApplicationContext context = this.applicationContext; Assert.state(context != null, "No ApplicationContext set"); //获取容器中所有EventListenerFactory 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)) { // 简单的说,就是把这个方法弄成一个可以执行的方法(主要和访问权限有关) // 这里注意:若你是JDK的代理类,请不要在实现类里书写@EventListener注解的监听器,否则会报错的。(CGLIB代理的木关系) Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); //利用EventListenerFactory创建ApplicationListener,详情后面说 ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); //如果ApplicationListener是ApplicationListenerMethodAdapter类,那么执行其init方法 if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } //放到容器中 context.addApplicationListener(applicationListener); //@EventListener方法只能解析一次 break; } } } if (logger.isDebugEnabled()) { logger.debug(); } } } } }
注意:@EventListener方法只要有到一个可以解析他的EventListenerFactory,就不会让其他EventListenerFactory解析他了
所以如果容器中存在多个EventListenerFactory,我要注意他的顺序
2.2 EventListenerFactory解析@EventListener
EventListenerFactory 有2个实现类 DefaultEventListenerFactory 和 TransactionalEventListenerFactory
DefaultEventListenerFactory:是处理 @EventListener,Spring默认就有
TransactionalEventListenerFactory:是处理@TransactionalEventListener的,Spring默认是没有的,
如果想要使用 @TransactionalEventListener 注解,就要注册一个TransactionalEventListenerFactory,也就是在启动类加上 @EnableTransactionManagement 注解
public interface EventListenerFactory { //是否支持当前方法 boolean supportsMethod(Method method); //生成一个ApplicationListener ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method); }
DefaultEventListenerFactory实现类
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered { private int order = LOWEST_PRECEDENCE; @Override public boolean supportsMethod(Method method) { return true; } @Override public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodAdapter(beanName, type, method); } }
ApplicationListenerMethodAdapter 中的一个 ApplicationListener,他是用来包装@EventListener标注的方法
public class ApplicationListenerMethodAdapter implements GenericApplicationListener { private final String beanName; //@EventListener方法所属bean的名字 private final Method method;//@EventListener标注的方法 private final Method targetMethod;//@EventListener标注的真实方法对象,防止其是代理方法 //方法申明,如public void demo.Ball.applicationContextEvent(demo.OrderEvent) private final AnnotatedElementKey methodKey; private final List<ResolvableType> declaredEventTypes;//存储方法的参数 private final String condition;//@EventListener的condition private final int order; private ApplicationContext applicationContext; private EventExpressionEvaluator evaluator;//@EventListener的EventExpressionEvaluator public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) { this.beanName = beanName; this.method = BridgeMethodResolver.findBridgedMethod(method); this.targetMethod = (!Proxy.isProxyClass(targetClass) ?AopUtils.getMostSpecificMethod(method, targetClass) : this.method); this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass); //获取方法上的@EventListener注解对象 EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class); this.declaredEventTypes = resolveDeclaredEventTypes(method, ann); this.condition = (ann != null ? ann.condition() : null); this.order = resolveOrder(this.targetMethod); } public void onApplicationEvent(ApplicationEvent event) { processEvent(event); } public void processEvent(ApplicationEvent event) { Object[] args = resolveArguments(event); //根据@EventListener的condition,判断是否要处理 if (shouldHandle(event, args)) { //调用方法 Object result = doInvoke(args); if (result != null) { //如果有监听器可以监听这个结果,那么可以触发那个监听器 handleResult(result); } else { logger.trace("No result object given - no result to handle"); } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具