Spring 事件发布机制

╰半夏微凉° 2024-04-06 11:37 170阅读 0赞

目录

事件驱动

使用事件机制

Java 事件使用

Spring 事件使用

使用 Aware

不使用 Aware

Spring 事件发布流程及源码解析

ApplicationEvent

ApplicationListener

监听者注册

ApplicationEventPublisher

AbstractApplicationContext

ApplicationEventMulticaster

retrieveApplicationListeners

事件发布的流程

观察者模式的事件思想

观察者模式作为对象间 一对多 依赖关系的实现。在观察者模式中,被观察者相当于事件中的时间发布者,而观察者相当于事件中的监听者。因此可以说:观察者模式就是事件驱动机制的一种体现。

事件驱动

事件驱动一个常见的形式就是 发布-订阅 模式,在跨进程的通信间,我们常常使用 消息队列 来实现消息的发布订阅。目前主流的框架中,均采用消息的 发布-订阅 模式来进行大型分布式项目的解耦。使得数据生产方和发送方分离,同时 MQ 还能起到削峰的作用。同一进程内很多时候也需要这种事件驱动机制来进行解耦

使用事件机制

事件机制主要由三个部分组成:事件源、事件对象、监听器

  • 事件源:事件发生的起源
  • 事件对象:事件实体,事件对象会持有一个事件源
  • 监听器:监听事件对象,对事件对象进行处理

Java 事件使用

Java 提供了关于事件相关的两个接口:

  • EventObject:事件对象,自定义事件需要继承该类
  • EventListener:事件监听器接口

由于事件源 Source 不需要实现任何接口,所以 Java 中没有给出相应的定义

一个利用 Java 原生实现事件的例子:

  1. import java.util.EventObject;
  2. /**
  3. * @Author: chenyang
  4. * @DateTime: 2022/9/21 10:08
  5. * @Description: 事件对象
  6. */
  7. public class JavaEvent extends EventObject {
  8. private String msg;
  9. /**
  10. * Constructs a prototypical Event.
  11. *
  12. * @param source The object on which the Event initially occurred.
  13. * @throws IllegalArgumentException if source is null.
  14. */
  15. public JavaEvent(Object source, String msg) {
  16. super(source);
  17. this.msg = msg;
  18. }
  19. public String getMsg() {
  20. return msg;
  21. }
  22. }
  23. import com.yang.common.event.JavaEvent;
  24. import java.util.EventListener;
  25. /**
  26. * @Author: chenyang
  27. * @DateTime: 2022/9/21 10:09
  28. * @Description: 事件监听者,按照 Java 规范应实现 EventListener 接口
  29. */
  30. public class JavaListener implements EventListener {
  31. public void handlerEvent(JavaEvent event){
  32. System.out.println("Java Event msg : " + event.getMsg());
  33. }
  34. }
  35. import com.yang.common.event.JavaEvent;
  36. import com.yang.common.listener.JavaListener;
  37. import java.util.EventListener;
  38. import java.util.HashSet;
  39. /**
  40. * @Author: chenyang
  41. * @DateTime: 2022/9/21 10:12
  42. * @Description: 事件源
  43. */
  44. public class JavaSource {
  45. private static HashSet<EventListener> set = new HashSet<>();
  46. public void addListener(EventListener listener){
  47. set.add(listener);
  48. }
  49. public void publishEvent(JavaEvent event){
  50. for (EventListener listener : set) {
  51. ((JavaListener)listener).handlerEvent(event);
  52. }
  53. }
  54. }
  55. public class Main {
  56. public static void main(String[] args) {
  57. JavaSource source = new JavaSource();
  58. JavaListener listener = new JavaListener();
  59. source.addListener(listener);
  60. source.publishEvent(new JavaEvent(source, "SAY MY NAME !!!"));
  61. }
  62. }

Spring 事件使用

Spring 提供了事件相关的接口和类,在 Spring 中可以通过实现接口来实现事件的 发布-订阅。Spring 的事件机制是以 Java 的事件机制为基础按需进行了扩展。

Spring 中与事件相关的定义如下:

  • ApplicationEvent:继承 ObjectEvent 类,事件源应该继承该类。
  • ApplicationListener:事件监听者,该类接受一个泛型,供 ApplicationEventPublisher 在发布事件时选择 EventListener。
  • ApplicationEventPublisher:封装发布事件的方法,通知所有在 Spring 中注册的该事件的监听者进行处理。
  • ApplicationEventPublisherAware:Spring 提供的 Aware 接口之一,实现该接口的 Bean 可以获取 ApplicationEventPublisher 并进行发布事件。

使用 Aware

一个利用 Spring 事件机制进行事件发布-订阅的例子:

  1. import org.springframework.context.ApplicationEvent;
  2. /**
  3. * @Author: chenyang
  4. * @DateTime: 2022/9/21 11:07
  5. * @Description: 事件对象
  6. */
  7. public class SpringEventAware extends ApplicationEvent {
  8. private String msg;
  9. public SpringEventAware(Object source, String msg) {
  10. super(source);
  11. this.msg = msg;
  12. }
  13. public SpringEventAware(Object source) {
  14. super(source);
  15. }
  16. public String getMsg() {
  17. return msg;
  18. }
  19. }
  20. import com.yang.common.event.SpringEvent;
  21. import org.springframework.context.ApplicationListener;
  22. import org.springframework.stereotype.Component;
  23. /**
  24. * @Author: chenyang
  25. * @DateTime: 2022/9/21 11:08
  26. * @Description: 事件监听者,事件监听者实现ApplicationListener<E extends ApplicationEvent>, 交由 Spring 进行管理,无需自己进行监听器的注册与通知过程
  27. */
  28. @Component
  29. public class SpringListenerAware implements ApplicationListener<SpringEventAware> {
  30. @Override
  31. public void onApplicationEvent(SpringEventAware event) {
  32. System.out.println("publish event, msg is : " + event.getMsg());
  33. }
  34. }
  35. import com.yang.common.event.SpringEvent;
  36. import org.springframework.context.ApplicationEventPublisher;
  37. import org.springframework.context.ApplicationEventPublisherAware;
  38. import org.springframework.stereotype.Component;
  39. /**
  40. * @Author: chenyang
  41. * @DateTime: 2022/9/21 11:09
  42. * @Description: 事件源
  43. */
  44. @Component
  45. public class SpringPublishAware implements ApplicationEventPublisherAware {
  46. private ApplicationEventPublisher applicationEventPublisher;
  47. public void publishEvent(String msg){
  48. applicationEventPublisher.publishEvent(new SpringEventAware(this, msg));
  49. }
  50. @Override
  51. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  52. this.applicationEventPublisher = applicationEventPublisher;
  53. }
  54. }
  55. @Autowired
  56. private SpringPublishAware springPublishAware;
  57. @Test
  58. void contextLoads2() {
  59. springPublishAware.publishEvent("通过 Spring 实现发布订阅");
  60. }

不使用 Aware

  1. @Data
  2. public class Task {
  3. private String name;
  4. private String address;
  5. }
  6. public class SpringEvent extends ApplicationEvent {
  7. private Task task;
  8. public SpringEvent(Task task) {
  9. super(task);
  10. this.task = task;
  11. }
  12. public Task getTask() {
  13. return task;
  14. }
  15. }
  16. @Component
  17. public class SpringListener implements ApplicationListener<SpringEvent> {
  18. @Override
  19. public void onApplicationEvent(SpringEvent event) {
  20. Task task = event.getTask();
  21. System.err.println("事件接受任务");
  22. System.err.println(task);
  23. System.err.println("任务完成");
  24. }
  25. }
  26. @Autowired
  27. private ApplicationEventPublisher publisher;
  28. @Test
  29. void contextLoads3() {
  30. Task task = new Task();
  31. task.setName("admin");
  32. task.setAddress("unknown area");
  33. SpringEvent event = new SpringEvent(task);
  34. System.out.println("开始发布任务");
  35. publisher.publishEvent(event);
  36. System.out.println("发布任务完成");
  37. }

以上代码中,可以看到。在 Spring 框架使用事件与在 Java 中使用时间机制其实并没有什么不同,均由 事件源、事件对象以及事件监听者组成。与 Java 原生提供的事件机制不同的是,Spring 中提供了 ApplicationEvent 类作为基类,开发者可以以此为基础定义自己的自定义事件。

在 Spring 中,继承自 ApplicationEvent 的事件对象的监听者,可以由 Spring 容器进行管理,并在发布时通过 ApplicationEventPublisher 进行发布。这就避免了我们自己实现监听者的注册和通知过程,免去了很多繁杂的过程,使得更专心于业务本身。

#

Spring 事件发布流程及源码解析

ApplicationEvent

  1. /**
  2. * Class to be extended by all application events. Abstract as it
  3. * doesn't make sense for generic events to be published directly.
  4. *
  5. * @author Rod Johnson
  6. * @author Juergen Hoeller
  7. */
  8. public abstract class ApplicationEvent extends EventObject {
  9. /** use serialVersionUID from Spring 1.2 for interoperability */
  10. private static final long serialVersionUID = 7099057708183571937L;
  11. /** System time when the event happened */
  12. private final long timestamp;
  13. /**
  14. * Create a new ApplicationEvent.
  15. * @param source the object on which the event initially occurred (never {@code null})
  16. */
  17. public ApplicationEvent(Object source) {
  18. super(source);
  19. this.timestamp = System.currentTimeMillis();
  20. }
  21. /**
  22. * Return the system time in milliseconds when the event happened.
  23. */
  24. public final long getTimestamp() {
  25. return this.timestamp;
  26. }
  27. }

ApplicationEvent 继承了 JDK 中的事件对象 EventObject,在 Spring 中所有事件对象均应继承自 ApplicationEvent。在Spring基础上,其增加了事件发生时的时间戳属性以及序列化ID,并提供了通过事件源进行构建的构造方法。 Spring 中的 ApplicationEvent 设置成抽象类,由于一个单独的 ApplicationEvent 是没有任何语义的,所以需要根据不同场景进行扩展,在其之上为事件赋予意义。此类的说明中,作者也很好的说明了这一点。

ApplicationListener

JDK 中提供了 EventListener 接口,作为事件监听者标记。Spring 在 EventListener 接口的基础上,提供了 ApplicationListener 接口。该接口接收一个 ApplicationEvent 的子类,完成事件的监听流程。具体源代码如下:

  1. /**
  2. * Interface to be implemented by application event listeners.
  3. * Based on the standard {@code java.util.EventListener} interface
  4. * for the Observer design pattern.
  5. *
  6. * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
  7. * that it is interested in. When registered with a Spring ApplicationContext, events
  8. * will be filtered accordingly, with the listener getting invoked for matching event
  9. * objects only.
  10. *
  11. * @author Rod Johnson
  12. * @author Juergen Hoeller
  13. * @param <E> the specific ApplicationEvent subclass to listen to
  14. * @see org.springframework.context.event.ApplicationEventMulticaster
  15. */
  16. @FunctionalInterface
  17. public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
  18. /**
  19. * Handle an application event.
  20. * @param event the event to respond to
  21. */
  22. void onApplicationEvent(E event);
  23. }

该接口是一个函数型接口,提供了一个 onApplicationEvent(E extends Application) 方法定义,所有自行实现的监听者均需要实现该接口,并在该方法中进行事件的处理。

监听者注册

Spring 中,不需要我们手动进行监听器注册。ApplicationListener 对象一旦在 Spring 容器中被注册,Spring 会进行监听器的注册,实现事件的监听。

在介绍监听者注册流程之前,首先需要介绍介绍一下 org.springframework.context.event.ApplicationEventMulticaster,其主要定义了管理事件监听者,与发布事件到监听者的相关操作,若没有定义,Spring 容器将默认实例化 SimpleApplicationEventMulticaster

在 Spring 中,初始化容器时会调用 org.springframework.context.ConfigurableApplicationContext 接口中的 reFresh() 方法进行 Bean的加载,该方法会进行事件的监听注册。具体代码如下:

监听者注册的代码位于 org.springframework.context.supportAbstractApplicationContext 类的 refresh() 方法,如下:

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
  5. // Prepare this context for refreshing.
  6. prepareRefresh();
  7. // Tell the subclass to refresh the internal bean factory.
  8. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  9. // Prepare the bean factory for use in this context.
  10. prepareBeanFactory(beanFactory);
  11. try {
  12. // Allows post-processing of the bean factory in context subclasses.
  13. postProcessBeanFactory(beanFactory);
  14. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
  15. // Invoke factory processors registered as beans in the context.
  16. invokeBeanFactoryPostProcessors(beanFactory);
  17. // Register bean processors that intercept bean creation.
  18. registerBeanPostProcessors(beanFactory);
  19. beanPostProcess.end();
  20. // Initialize message source for this context.
  21. initMessageSource();
  22. // Initialize event multicaster for this context.
  23. initApplicationEventMulticaster();
  24. // Initialize other special beans in specific context subclasses.
  25. onRefresh();
  26. // Check for listener beans and register them.
  27. registerListeners();
  28. // Instantiate all remaining (non-lazy-init) singletons.
  29. finishBeanFactoryInitialization(beanFactory);
  30. // Last step: publish corresponding event.
  31. finishRefresh();
  32. }
  33. catch (BeansException ex) {
  34. if (logger.isWarnEnabled()) {
  35. logger.warn("Exception encountered during context initialization - " +
  36. "cancelling refresh attempt: " + ex);
  37. }
  38. // Destroy already created singletons to avoid dangling resources.
  39. destroyBeans();
  40. // Reset 'active' flag.
  41. cancelRefresh(ex);
  42. // Propagate exception to caller.
  43. throw ex;
  44. }
  45. finally {
  46. // Reset common introspection caches in Spring's core, since we
  47. // might not ever need metadata for singleton beans anymore...
  48. resetCommonCaches();
  49. contextRefresh.end();
  50. }
  51. }
  52. }

在 refresh() 方法的代码中,注意以下两项:

  • 调用 initApplicationEventMulticaster() 方法初始化一个 ApplicationEventMulticaster,默认情况下初始化为 SimpleApplicationEventMulticaster。
  • 调用 registerListeners() 方法进行事件监听者的注册。该方法具体实现如下:

    protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {

    1. this.applicationEventMulticaster =
    2. beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    3. if (logger.isTraceEnabled()) {
    4. logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    5. }

    }
    else {

    1. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    2. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    3. if (logger.isTraceEnabled()) {
    4. logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
    5. "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    6. }

    }
    }

    protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {

    1. getApplicationEventMulticaster().addApplicationListener(listener);

    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {

    1. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);

    }

    // Publish early application events now that we finally have a multicaster…
    Set earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {

    1. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
    2. getApplicationEventMulticaster().multicastEvent(earlyEvent);
    3. }

    }
    }

由上文代码可见,注册监听者的过程主要可以分为以下三部分:

  • 添加容器中指定的监听器,通常这部分添加的监听器由 Spring 控制;
  • BeanFactory 中获取全部实现了 ApplicationListener 接口的 BeanNames,并把其推送给 ApplicationEventMulticaster
  • 若有需要立即执行的事件,直接执行这些事件的发布

以上三步就是 Spring 在初始化 Beans 时进行的事件监听者注册相关逻辑。在 Bean 加载过程中,就完成了事件的监听者注册,我们无需另外自行为自定义事件注册监听者。

ApplicationEventPublisher

在 Spring 中,发布一个自定义事件的过程可以由以下一行代码概括:

  1. applicationEventPublisher.publishEvent(new SpringEvent(msg));
  2. // applicationEventPublisher.publishEvent(new SpringEvent(this, msg));

其中,applicationEventPublisher是通过 Spring 注入的 ApplicationEventPublisher 实例。在事件源中通过上述代码,便可以在 Spring 中发布一个自定义事件。使用其publishEvent方法发布任务后,代码进入了org.springframework.context.support.AbstractApplicationContext 逻辑内。

AbstractApplicationContext

整个事件发布逻辑都在这个类以及其子类中,其最终发布事件的方法是publishEvent(Object event, @Nullable ResolvableType eventType)

  1. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  2. Assert.notNull(event, "Event must not be null");
  3. // 类型转换
  4. ApplicationEvent applicationEvent;
  5. if (event instanceof ApplicationEvent) {
  6. applicationEvent = (ApplicationEvent) event;
  7. }
  8. else {
  9. applicationEvent = new PayloadApplicationEvent<>(this, event);
  10. if (eventType == null) {
  11. eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
  12. }
  13. }
  14. // 在早期事件,容器初始化时候使用,可以忽略
  15. if (this.earlyApplicationEvents != null) {
  16. this.earlyApplicationEvents.add(applicationEvent);
  17. }
  18. else {
  19. // 进行任务广播的主要逻辑
  20. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  21. }
  22. // 方便使用父类进行发布事件,非重点
  23. if (this.parent != null) {
  24. if (this.parent instanceof AbstractApplicationContext) {
  25. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  26. }
  27. else {
  28. this.parent.publishEvent(event);
  29. }
  30. }
  31. }

具体可以分为以下三步:

  1. 将事件分为 ApplicationEventPayloadApplicationEvent 两部分。其中,我们在 Spring 中自定义的事件均为 ApplicationEvent 类型,PayloadApplicationEvent 通常为 Spring 框架自身的事件;
  2. multicaster 若还未加载,将其存入 EarlyApplicationEvents 队列,并在 multicaster 初始化成功后立即发布;
  3. 同样发布事件到父级 ApplicationContext 打法

以上三步便是发布一个事件的过程,由于我们发布的自定义事件通常在容器加载之后,且自定义事件均是 ApplicationEvent 过程,所以通常涉及到的仅是 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType) 这一行,这一行的内容分为两个部分:

  1. getApplicationEventMulticaster():获得容器中的ApplicationEventMulticaster。此内容主要Spring用来辅助发布任务的工具类
  2. ApplicationEventMulticaster.multicastEvent(applicationEvent, eventType):真正进行事件发布的内容。

ApplicationEventMulticaster

其为org.springframework.context.event.AbstractApplicationEventMulticaster实现类,主要为了辅助事件进行发布, 其内部发布任务主要核心逻辑在multicastEvent中。

  1. @Override
  2. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  3. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  4. Executor executor = getTaskExecutor();
  5. for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  6. if (executor != null) {
  7. executor.execute(() -> invokeListener(listener, event));
  8. }
  9. else {
  10. invokeListener(listener, event);
  11. }
  12. }
  13. }

此处以 SimpleApplicationEventMulticaster 中的方法定义为例,作为默认注入的类型,通常我们在默认情况下的事件发布流程均遵循该实现。 从程序中可以看出,multicastEvent的主要逻辑可以分为三部分:

  1. 获取事件类型,主要用来获得Spring Event的实际类型。resolveDefaultEventType(event))
  2. getApplicationListeners(event, type)根据事件和事件类型去获得此事件和事件类型的监听器
  3. 遍历监听者集合,通过 multicaster 内持有的 Executor 进行通知,此处最后调用了 ApplicationListener 中的 onApplicationEvent 方法,这一方法正是我们在自定义 ApplicationListener 时必须要覆写的方法。

AbstractApplicationEventMulticaster

获取监听器的主要逻辑在org.springframework.context.event.AbstractApplicationEventMulticaster中的getApplicationListeners(event, type)

  1. protected Collection<ApplicationListener<?>> getApplicationListeners(
  2. ApplicationEvent event, ResolvableType eventType) {
  3. Object source = event.getSource();
  4. Class<?> sourceType = (source != null ? source.getClass() : null);
  5. ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
  6. // Potential new retriever to populate
  7. CachedListenerRetriever newRetriever = null;
  8. // Quick check for existing entry on ConcurrentHashMap
  9. CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
  10. if (existingRetriever == null) {
  11. // Caching a new ListenerRetriever if possible
  12. if (this.beanClassLoader == null ||
  13. (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
  14. (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
  15. newRetriever = new CachedListenerRetriever();
  16. existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
  17. if (existingRetriever != null) {
  18. newRetriever = null; // no need to populate it in retrieveApplicationListeners
  19. }
  20. }
  21. }
  22. if (existingRetriever != null) {
  23. Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
  24. if (result != null) {
  25. return result;
  26. }
  27. // If result is null, the existing retriever is not fully populated yet by another thread.
  28. // Proceed like caching wasn't possible for this current local attempt.
  29. }
  30. return retrieveApplicationListeners(eventType, sourceType, newRetriever);
  31. }

大致流程: 通过时间类型和事件中的数据源类型,构建一个缓存key,先去缓存中获取有无此key对应的事件处理器。 如果不存在则构建一个新的ListenerRetriever,然后调用retrieveApplicationListeners方法获得监听的listener。

retrieveApplicationListeners

  1. private Collection<ApplicationListener<?>> retrieveApplicationListeners(
  2. ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
  3. List<ApplicationListener<?>> allListeners = new ArrayList<>();
  4. Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
  5. Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
  6. Set<ApplicationListener<?>> listeners;
  7. Set<String> listenerBeans;
  8. synchronized (this.defaultRetriever) {
  9. listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
  10. listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
  11. }
  12. // Add programmatically registered listeners, including ones coming
  13. // from ApplicationListenerDetector (singleton beans and inner beans).
  14. for (ApplicationListener<?> listener : listeners) {
  15. if (supportsEvent(listener, eventType, sourceType)) {
  16. if (retriever != null) {
  17. filteredListeners.add(listener);
  18. }
  19. allListeners.add(listener);
  20. }
  21. }
  22. // Add listeners by bean name, potentially overlapping with programmatically
  23. // registered listeners above - but here potentially with additional metadata.
  24. if (!listenerBeans.isEmpty()) {
  25. ConfigurableBeanFactory beanFactory = getBeanFactory();
  26. for (String listenerBeanName : listenerBeans) {
  27. try {
  28. if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
  29. ApplicationListener<?> listener =
  30. beanFactory.getBean(listenerBeanName, ApplicationListener.class);
  31. if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
  32. if (retriever != null) {
  33. if (beanFactory.isSingleton(listenerBeanName)) {
  34. filteredListeners.add(listener);
  35. }
  36. else {
  37. filteredListenerBeans.add(listenerBeanName);
  38. }
  39. }
  40. allListeners.add(listener);
  41. }
  42. }
  43. else {
  44. // Remove non-matching listeners that originally came from
  45. // ApplicationListenerDetector, possibly ruled out by additional
  46. // BeanDefinition metadata (e.g. factory method generics) above.
  47. Object listener = beanFactory.getSingleton(listenerBeanName);
  48. if (retriever != null) {
  49. filteredListeners.remove(listener);
  50. }
  51. allListeners.remove(listener);
  52. }
  53. }
  54. catch (NoSuchBeanDefinitionException ex) {
  55. // Singleton listener instance (without backing bean definition) disappeared -
  56. // probably in the middle of the destruction phase
  57. }
  58. }
  59. }
  60. AnnotationAwareOrderComparator.sort(allListeners);
  61. if (retriever != null) {
  62. if (filteredListenerBeans.isEmpty()) {
  63. retriever.applicationListeners = new LinkedHashSet<>(allListeners);
  64. retriever.applicationListenerBeans = filteredListenerBeans;
  65. }
  66. else {
  67. retriever.applicationListeners = filteredListeners;
  68. retriever.applicationListenerBeans = filteredListenerBeans;
  69. }
  70. }
  71. return allListeners;
  72. }

在这个方法中主要进行的逻辑就很简单了。主要通过循环Listeners来进行监听匹配。而Listeners的来源主要为两部分:

  1. listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
  2. listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);

一部分为容器中已经存在的监听器,一部分是监听器bean的字符串标识的名称。 applicationListenerBeans主要为了处理那些声明后还是还没有被添加进监听器集合中的bean。

事件发布的流程

fc0b6f2af48346f6b887825b6eff8741.png

实战

  1. public class UserEvent {
  2. private String username;
  3. private String password;
  4. }
  5. @Component
  6. public class UserListener implements ApplicationListener<PayloadApplicationEvent<UserEvent>> {
  7. @Async
  8. @Override
  9. public void onApplicationEvent(PayloadApplicationEvent<UserEvent> event) {
  10. UserEvent payload = event.getPayload();
  11. System.out.println("result: " + payload);
  12. }
  13. }
  14. public interface DomainEventPublisher {
  15. void publish(Object object);
  16. }
  17. @ConditionalOnMissingBean(DomainEventPublisher.class)
  18. @Configuration
  19. public class EventPublisherConfig{
  20. private final ApplicationEventPublisher applicationEventPublisher;
  21. @Autowired
  22. public EventPublisherConfig(ApplicationEventPublisher applicationEventPublisher) {
  23. this.applicationEventPublisher = applicationEventPublisher;
  24. }
  25. @Bean
  26. public DomainEventPublisher domainEventPublisher(){
  27. return event -> {
  28. System.out.println("事件发布:" + event);
  29. applicationEventPublisher.publishEvent(event);
  30. };
  31. }
  32. }
  33. @Autowired
  34. private DomainEventPublisher domainEventPublisher;
  35. @Test
  36. void contextLoads() {
  37. UserEvent userEvent = new UserEvent();
  38. userEvent.setUsername("username");
  39. userEvent.setPassword("123");
  40. System.out.println("事件开始");
  41. domainEventPublisher.publish(userEvent);
  42. System.out.println("事件结束");
  43. }

发表评论

表情:
评论列表 (有 0 条评论,170人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring 事件发布

    前言 事件发布是 Spring 框架中最容易被忽视的功能之一,但实际上它是一个很有用的功能。使用事件机制可以将同一个应用系统内互相耦合的代码进行解耦,并且可以将事件与 S

    相关 Spring事件机制

    1.背景 事件驱动的一个常见形式便是发布-订阅模式。在跨进程的通信间,我们通常采用引入 MQ (消息队列) 来实现消息的发布和订阅。目前主流应用的架构中,均采用消息的发布

    相关 spring事件机制

    事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型;理解它的几个关键点: 1. 首先是一种对象间的一对多的关系;最简单的如交通信号灯,信号灯是目

    相关 spring事件机制

    事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型;理解它的几个关键点: 首先是一种对象间的一对多的关系;最简单的如交通信号灯,信号灯是目标