java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring自定义监听器

Spring中如何自定义监听器

作者:懒惰蜗牛

这篇文章将通过一个简单的自定义的监听器,从源码的角度分析一下Spring中监听的整个过程,分析监听的作用,感兴趣的小伙伴可以了解一下

前言

通过一个简单的自定义的监听器,从源码的角度分一下Spring中监听的整个过程,分析监听的作用。

一、自定义监听案例

1.1定义事件

 package com.lazy.snail;
 ​
 import lombok.Getter;
 import org.springframework.context.ApplicationEvent;
 ​
 /**
  * @ClassName UserRegisteredEvent
  * @Description TODO
  * @Author lazysnail
  * @Date 2024/11/8 10:37
  * @Version 1.0
  */
 @Getter
 public class UserRegisteredEvent extends ApplicationEvent {
     private final String username;
 ​
     public UserRegisteredEvent(Object source, String username) {
         super(source);
         this.username = username;
     }
 }

1.2定义监听

 package com.lazy.snail;
 ​
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
 ​
 /**
  * @ClassName UserRegisteredListener
  * @Description TODO
  * @Author lazysnail
  * @Date 2024/11/8 10:36
  * @Version 1.0
  */
 @Component
 public class UserRegisteredListener {
     @EventListener
     public void handleUserRegisterEvent(UserRegisteredEvent event) {
         System.out.println("用户注册成功,发送邮件通知");
     }
 }

1.3定义用户服务(发布事件)

 package com.lazy.snail;
 ​
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 ​
 /**
  * @ClassName UserService
  * @Description TODO
  * @Author lazysnail
  * @Date 2024/11/8 10:37
  * @Version 1.0
  */
 @Service
 public class UserService {
     private final ApplicationEventPublisher eventPublisher;
 ​
     public UserService(ApplicationEventPublisher eventPublisher) {
         this.eventPublisher = eventPublisher;
     }
 ​
     public void registerUser(String username) {
         // 用户注册逻辑
         System.out.println("Registering user: " + username);
 ​
         // 发布用户注册事件
         eventPublisher.publishEvent(new UserRegisteredEvent(this, username));
     }
 }

1.4测试类

 package com.lazy.snail;
 ​
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 ​
 @Slf4j
 public class SpringTest {
 ​
     @Test
     void test() {
         ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
         context.getBean(UserService.class).registerUser("lazysnail");
     }
 }

1.5测试结果

二、事件监听流程

2.1容器启动阶段

2.1.1事件监听方法处理器及默认事件监听工厂

事件监听方法处理器及默认事件监听工厂的bean定义信息注册

事件监听方法处理器会在后续用于处理自定义监听中的@EventListener注解

默认事件监听工厂会用于将自定义监听封装为ApplicationListenerMethodAdapter

 public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
             BeanDefinitionRegistry registry, @Nullable Object source) {
     // 省略部分代码...
     
     // 事件监听方法处理器
     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));
     }
     
     // 默认事件监听工厂
     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;
 }

事件监听方法处理器及默认事件监听工厂的实例化

refresh方法中,invokeBeanFactoryPostProcessors处理BeanFactoryPostProcessor(EventListenerMethodProcessor实现了BeanFactoryPostProcessor)

实例化EventListenerMethodProcessor

调用EventListenerMethodProcessor的postProcessBeanFactory实例化DefaultEventListenerFactory

 // EventListenerMethodProcessor
 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
     this.beanFactory = beanFactory;
 ​
     Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
     List<EventListenerFactory> factories = new ArrayList<>(beans.values());
     AnnotationAwareOrderComparator.sort(factories);
     this.eventListenerFactories = factories;
 }

2.1.3应用事件广播器创建

容器刷新时,initApplicationEventMulticaster创建SimpleApplicationEventMulticaster

注册单例到容器

 // AbstractApplicationContext
 public void refresh() throws BeansException, IllegalStateException {
     // 为容器初始化事件广播器
     initApplicationEventMulticaster();
 }
 // AbstractApplicationContext
 protected void initApplicationEventMulticaster() {
     this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
     beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
     if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                 "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
     }
 }

SimpleApplicationEventMulticaster从AbstractApplicationEventMulticaster继承过来一个defaultRetriever对象

defaultRetriever中封装了监听器集合

 private class DefaultListenerRetriever {
 ​
     public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
 ​
     public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
 }

监听集合中的监听是何时添加的

提前实例化单例后EventListenerMethodProcessor对容器中所有监听处理时添加

 // DefaultListableBeanFactory
 public void preInstantiateSingletons() throws BeansException {
     // 省略部分代码...
     
     // EventListenerMethodProcessor
     for (String beanName : beanNames) {
         Object singletonInstance = getSingleton(beanName);
         if (singletonInstance instanceof SmartInitializingSingleton) {
             StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
                     .tag("beanName", beanName);
             SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
             if (System.getSecurityManager() != null) {
                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                     smartSingleton.afterSingletonsInstantiated();
                     return null;
                 }, getAccessControlContext());
             } else {
                 // 单例实例化后处理
                 smartSingleton.afterSingletonsInstantiated();
             }
             smartInitialize.end();
         }
     }
 }

监听器的创建

 // EventListenerMethodProcessor
 public void afterSingletonsInstantiated() {
     ConfigurableListableBeanFactory beanFactory = this.beanFactory;
     Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
     String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
     // 处理UserRegisteredListener
     for (String beanName : beanNames) {
         // 省略部分代码...
         processBean(beanName, type);
     }
 }
 ​
 private void processBean(final String beanName, final Class<?> targetType) {
     if (!this.nonAnnotatedClasses.contains(targetType) &&
             AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
             !isSpringContainerClass(targetType)) {
 ​
         Map<Method, EventListener> annotatedMethods = null;
         // 省略部分代码...
         
         // @EventListener注解的方法(注解上的属性)
         annotatedMethods = MethodIntrospector.selectMethods(targetType,
                     (MethodIntrospector.MetadataLookup<EventListener>) method ->
                             AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
 ​
         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));
                         // 事件监听工厂创建应用监听器 ApplicationListenerMethodAdapter
                         ApplicationListener<?> applicationListener =
                                 factory.createApplicationListener(beanName, targetType, methodToUse);
                         if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                             ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                         }
                         // 添加到应用上下文
                         context.addApplicationListener(applicationListener);
                         break;
                     }
                 }
             }
         }
     }
 }

2.2客户端调用阶段

发布事件

 // AbstractApplicationContext
 protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
     getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
 }

拿到内部应用事件广播器(SimpleApplicationEventMulticaster)

广播器广播事件

 // SimpleApplicationEventMulticaster
 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);
         }
     }
 }

获取监听

检索应用监听器

直接从检索器(defaultRetriever)中取出监听

 /**
  * 根据给定的事件、源(我理解是容器)检索监听器
  * 
  */
 // AbstractApplicationEventMulticaster
 private Collection<ApplicationListener<?>> retrieveApplicationListeners(
             ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
 ​
     List<ApplicationListener<?>> allListeners = new ArrayList<>();
     Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
     Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
 ​
     Set<ApplicationListener<?>> listeners;
     Set<String> listenerBeans;
     synchronized (this.defaultRetriever) {
         // 默认检索器中获取应用监听,监听已经在Spring启动阶段注册完成
         listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
         listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
     }
 ​
     // 省略部分代码...
 ​
     AnnotationAwareOrderComparator.sort(allListeners);
     if (retriever != null) {
         if (filteredListenerBeans.isEmpty()) {
             retriever.applicationListeners = new LinkedHashSet<>(allListeners);
             retriever.applicationListenerBeans = filteredListenerBeans;
         }
         else {
             retriever.applicationListeners = filteredListeners;
             retriever.applicationListenerBeans = filteredListenerBeans;
         }
     }
     return allListeners;
 }       

调用监听

invokeListener

三、总结

个人理解:

事件发布是一个抽象的概念,真正将事件发布出去的是SimpleApplicationEventMulticaster,发布事件实际做的事情,找到监听器,过滤出能够处理这个事件的监听器,然后执行监听器中针对这个事件的业务逻辑。

3.1监听流程总结

3.1.1. Spring 容器启动

3.1.2. 监听器注册

在 Spring 中,可以通过以下几种方式注册监听器:

监听器的作用:每当发布的事件类型与监听器泛型参数中的事件类型匹配时,监听器的 onApplicationEvent 方法就会被调用。

3.1.3. 事件发布

发布者:Spring 中的任何组件都可以通过 ApplicationEventPublisher 发布事件。通常,ApplicationContext 本身实现了 ApplicationEventPublisher,可以直接调用 publishEvent() 发布事件。

事件传播器:默认情况下,Spring 使用 SimpleApplicationEventMulticaster 作为事件传播器,它负责查找符合条件的监听器并将事件分发给它们。

发布事件的方法:通过 applicationContext.publishEvent(new CustomEvent(this)) 来发布事件。

3.1.4. 事件广播给监听器

3.1.5. 监听器处理事件

3.1.6. 事件传播的扩展

在某些场景中,一个事件的监听器可能会发布新的事件,这会形成事件链。Spring 容器会递归地将这些新事件广播给感兴趣的监听器。

3.2应用场景

3.2.1. 解耦业务逻辑

3.2.2. 事务性事件

3.2.3. 异步处理任务

3.2.4. 应用启动或关闭事件

3.2.5. 状态变化或监控

3.2.6. 领域驱动设计(DDD)中的事件处理

3.2.7. 跨服务通信

3.2.8. 监听应用配置变化

3.2.9. 处理安全或认证事件

以上就是Spring中如何自定义监听器的详细内容,更多关于Spring自定义监听器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文