天天看點

淺談業務解耦小工具 - Spring Event

作者:閃念基因

一. 是什麼

官網定義

"An event is an object that is created when something notable happens within an application, such as a user clicking a button or an HTTP request arriving at a web server. An event listener is an object that listens for events, and the code that handles the event is the event handler. Event handlers are invoked by an event publisher. The act of invoking an event is called publishing an event."

該定義強調了事件、事件監聽器和事件處理器的概念,并将事件作為應用程式中有意義的操作所建立的對象。同時,事件監聽器和事件處理器的作用也被明确描述為監聽事件并做出響應。此外,官方定義還提到了事件釋出者和釋出事件的概念。

Spring Event 是 Spring 架構中的一個事件驅動模型,可以用來在不同的元件之間傳遞消息和響應事件。

優點:

  • 降低元件之間的耦合度:通過使用 Spring Event,元件之間不需要顯式地互相引用,而是通過事件進行互動,進而降低了它們之間的耦合度。
  • 提高應用程式的可擴充性:由于元件之間的耦合度降低,是以在應用程式需要進行擴充或修改時,更容易添加或删除元件。
  • 提高代碼的重用性:由于事件監聽器是一個單獨的元件,是以它可以被多個事件源重複利用,進而提高代碼的重用性。
  • 提供了異步事件處理的支援:Spring Event 可以提供異步事件處理的支援,進而避免事件處理的阻塞,提高應用程式的性能。
  • 友善進行事件的測試和模拟:由于事件機制是松散耦合的,是以很容易對事件進行測試和模拟,進而提高了代碼的可測試性。
  • 總的來說,Spring Event 提供了一種松散耦合的機制,通過事件的方式進行元件之間的互動,使得應用程式更加靈活、可擴充和可測試。

☢️缺點:

  • 過度使用事件機制可能導緻代碼複雜度增加:在一個應用程式中過度使用事件機制可能導緻代碼結構變得複雜,這可能會使程式的維護和擴充變得困難。
  • 可能會影響應用程式的性能:在事件進行中,當事件的數量較多時,事件監聽器的執行可能會占用較多的 CPU 資源,進而影響應用程式的性能。
  • 可能會導緻事件的亂序執行:由于 Spring Event 是基于觀察者模式實作的,是以事件監聽器之間的執行順序并不是确定的,這可能會導緻事件的亂序執行。
  • 可能會對調試造成一定的困難:由于事件機制中事件的觸發和處理過程通常是異步的,是以在調試應用程式時可能會遇到一些困難。

是以,開發人員在使用 Spring Event 時應該根據具體的業務需求和場景來判斷是否需要使用事件機制,并合理利用該機制來優化應用程式的架構。

二. 怎麼用

定義事件

繼承ApplicationEvent,将需要傳遞的事件資訊包裝為業務事件類,如下所示。

java複制代碼public class FinishLvEvent extends ApplicationEvent {

    /**
     * 闖關結果
     */
    private String result;

    /**
     * 事件處理後傳回内容容器
     */
    private Object response;

    //getter setter...

    public FinishLvEvent(Object source, String result, Object response) {
        super(source);
        this.result = result;
        this.response = response;
    }
}           

事件釋出

注入ApplicationEventPublisher,通過publishEvent方法即可釋出事件。ApplicationEventPublisher的一般實作是AbstractApplicationContext,即Spring容器本身就是可以發送Spring事件。

java複制代碼@Service
public class AuditService {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void audit(int auditStatus, long auditId) {
        // 修改資料庫稽核狀态
        auditMapper.updateStatusById(auditStatus, auditId);
        // 發送稽核事件
        applicationEventPublisher.publishEvent(new AuditEvent(this, auditStatus, auditId));
    }
}           

事件監聽

實作對應事件的監聽器,需要繼承ApplicationListener,并實作onApplicationEvent方法。通過泛型指定需要監聽的事件類。

java複制代碼@Component
public class AuditEventListener implements ApplicationListener<AuditEvent> {

    @Override
    public void onApplicationEvent(AuditEvent auditEvent) {
        // 事件處理
    }
}           

也可以使用@EventListener注解方法,将其包裝為事件處理器。它适用于:

1. 不想為每個事件處理都建立一個ApplicationListener實作類;

2. 希望支援更複雜的事件條件過濾。

@EventListener的classes屬性可以過濾事件類型,而condition屬性可以根據事件對象是否滿足條件表達式來過濾事件。

java複制代碼@Component
public class EventProcessor {

    @EventListener(classes={CustomEvent.class}, condition="#event.status==1")
    public void process(CustomEvent event) {
        // 事件處理
    }
}           

異步處理

預設情況下,ApplicationListener處理事件是同步執行的。如果要處理耗時操作,希望異步執行,有三種方案:

1. 自定義ApplicationEventMulticaster

後面可以看到,Spring容器會優先使用beanName為applicationEventMulticater 的bean作為事件轉發處理器,如果不存在則預設使用SimpleApplicationEventMulticaster作為事件轉發處理器,它預設是同步執行的。但它支援設定Executor,那麼我們可以将自定義的線程池處理器作為Executor,以此來支援異步執行。

java複制代碼@Configuration
public class Config {

    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticater() {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(Executors.newFixedThreadPool(1));  // 自定義線程池
        return multicaster;
    }
}           

不過這樣設定之後,所有Listener都是異步執行。對于需要同時支援異步和同步執行的應用,考慮下面的方案。

2. 手動送出線程池異步執行

适用于簡單的場景。但這樣對代碼的侵入性比較高,

java複制代碼private Executor executor = Executors.newFixedThreadPool(1);

public void onApplicationEvent(CustomEvent event) {
    executor.execute(() -> process(event));
}           

3. 使用@Async注解

對于@EventListener注解的方法處理器,可以使用@Async注解,使得方法調用變為異步調用。(需要在啟動類Application上使用@EnableAsync注解,引入對@Async的支援。)

三. 源碼分析

核心類、方法

淺談業務解耦小工具 - Spring Event
  • ApplicationEvent

抽象類:所有的 Spring Event 都是繼承自該抽象類。它定義了一個 source 字段,表示事件源,以及相關的 getter 和 setter 方法。

  • ApplicationListener

接口:所有的 Spring Event 監聽器都需要實作該接口,實作 onApplicationEvent() 方法來處理事件。

  • ApplicationEventPublisher

接口:事件釋出者,定義了 publishEvent() 方法,用于釋出事件。

  • ApplicationEventPublisherAware

接口:通過實作該接口,可以讓 bean 感覺到事件釋出者,并将其儲存在一個成員變量中。

  • ApplicationEventMulticaster

接口:事件廣播器,用于将事件廣播給所有的監聽器。Spring 預設提供了 SimpleApplicationEventMulticaster 和 AsyncApplicationEventMulticaster 兩種實作。

  • AbstractApplicationEventMulticaster

抽象類:實作了 ApplicationEventMulticaster 接口的大部分方法,提供了一些基礎的實作邏輯。SimpleApplicationEventMulticaster 和 AsyncApplicationEventMulticaster 都繼承自該類。

  • GenericApplicationListener

接口:它是 ApplicationListener 接口的子接口,定義了一個泛型類型 E,用于指定監聽的事件類型。

  • SimpleApplicationEventMulticaster

類:實作了 ApplicationEventMulticaster 接口,用于将事件廣播給所有的監聽器。

  • AsyncApplicationEventMulticaster

類:實作了 ApplicationEventMulticaster 接口,用于異步地将事件廣播給所有的監聽器。

  • ApplicationEventPublisherAwareProcessor

類:實作了 BeanPostProcessor 接口,用于将事件釋出者自動注入到實作了 ApplicationEventPublisherAware 接口的 bean 中。

這些類和接口是 Spring Event 的核心,它們提供了事件的定義、監聽器的注冊和處理、事件釋出者的注入等重要功能。

預留事件

Spring Framework 中預留了多個事件,包括但不限于以下事件:

ContextRefreshedEvent:在 ApplicationContext 被初始化或重新整理時,該事件被釋出。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發生。

ContextStartedEvent:在啟動時,該事件被釋出,即在調用 ConfigurableApplicationContext 接口中的 start() 方法時。

ContextStoppedEvent:在停止時,該事件被釋出,即在調用 ConfigurableApplicationContext 接口中的 stop() 方法時。

ContextClosedEvent:在 ApplicationContext 被關閉時,該事件被釋出。這也可以在 ConfigurableApplicationContext 接口中使用 close() 方法來發生。

RequestHandledEvent:在 Web 請求被處理後,該事件被釋出。此事件僅适用于使用 Spring 的 Web 子產品。

ServletRequestHandledEvent:在 Web 請求被處理後,該事件被釋出。此事件僅适用于使用 Spring 的 Web 子產品。

SessionDestroyedEvent:在 Web 會話被銷毀時,該事件被釋出。此事件僅适用于使用 Spring 的 Web 子產品。

基于預留事件進行擴充Demo

完成後釋出自定義事件。可以使用

@EventListener 注解或 ApplicationListener 接口來監聽 ContextRefreshedEvent 事件,例如:

java複制代碼@Component
public class MyContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 釋出自定義事件
        event.getApplicationContext().publishEvent(new MyContextRefreshedEvent(this));
    }
}           

建立一個繼承自 ApplicationListener<MyContextRefreshedEvent> 的自定義事件監聽器,并實作 onApplicationEvent 方法來執行自定義的初始化操作。例如,可以建立一個 MyContextRefreshedEventListener 類:

java複制代碼@Component
public class MyContextRefreshedEventListener implements ApplicationListener<MyContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(MyContextRefreshedEvent event) {
        // 執行自定義的初始化操作
        System.out.println("MyContextRefreshedEvent received, do some initialization...");
    }
}           

通過以上步驟,當 Spring 容器啟動完成後,會觸發 ContextRefreshedEvent 事件,進而釋出 MyContextRefreshedEvent 自定義事件,并通過自定義事件監聽器 MyContextRefreshedEventListener 來執行自定義的初始化操作。

事件釋出與轉發

淺談業務解耦小工具 - Spring Event

ApplicationEventPublisher

Spring容器(父類AbstractApplicationContext)把自身作為ApplicationEventPublisher類的實作注冊到容器中

java複制代碼// AbstractApplicationContext#prepareBeanFactory
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);           

最終将類型、執行個體注冊到:

java複制代碼private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);           

AbstractApplicationContext作為ApplicationEventPublisher,實作了publishEvent方法,将其轉發給内部實作:

  1. 包裝非ApplicationEvent對象為PayloadApplicationEvent
  2. 在Listener初始化之前儲存早期釋出的事件
  3. 在初始化之後直接給交給applicationEventMulticaster釋出事件
  4. 同時将事件釋出給父容器(如果有,且是AbstractApplicationContext實作)
java複制代碼// AbstractApplicationContext
@Override
public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

@Override
public void publishEvent(Object event) {
    publishEvent(event, null);
}
// 具體實作
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    // 包裝ApplicationEvent
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }
    // 考慮到部分事件在Listener注冊之前就釋出了,是以先儲存起來
    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);
        }
    }
}           

也就是事件轉發依賴ApplicationEventMulticaster對象。容器初始化過程中會先完成ApplicationEventMulticaster對象的初始化,再注冊Listener。

text複制代碼// AbstractApplicationContext
public void refresh() {
    prepareRefresh();
    ...
    initApplicationEventMulticaster();
    onRefresh();
    registerListeners(); // 注冊監聽器
    ...
}           

如果容器中已經注冊有名為applicationEventMulticaster的Bean,則使用它(我們可以通過這種方式注冊自定義的ApplicationEventMulticaster,比如添加線程處理器),否則預設使用SimpleApplicationEventMulticaster作為轉發器。

text複制代碼public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}           

将容器注冊的Listener和Listener Bean,注冊到applicationEventMulticaster。同時開始轉發早期收集的事件。

text複制代碼protected void registerListeners() {
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // 從容器中擷取實作ApplicationListener的Bean
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }
    // 初始化之前收集的事件,這時候開始轉發
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}           
關于earlyApplicationEventsAbstractApplicationContext的refresh()方法确定了容器初始化的流程,在prepareRefresh()中将earlyApplicationEvents初始化為空清單,再此之後初始化過程中發送的事件,都将儲存在earlyApplicationEvents中。而後續先初始化applicationEventMulticaster,再注冊完監聽器,此時會将earlyApplicationEvents中所有事件發送給監聽器,然後置為null,至此earlyApplicationEvents的任務就已經完成了。

SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster 繼承自AbstractApplicationEventMulticaster ,後者實作了Listener和Listener Bean注冊和移除、查找,前者在此基礎上,實作了事件轉發的功能。在multicastEvent方法中,周遊所有支援該事件類型的ApplicationListener,調用其onApplicationEvent方法。SimpleApplicationEventMulticaster 允許使用者設定Executor,使用Executor執行事件處理程式。

java複制代碼// SimpleApplicationEventMulticaster
@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(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 {
            // 執行 listener.onApplicationEvent(event);
            invokeListener(listener, event);
        }
    }
}           

AbstractApplicationEventMulticaster 的 defaultRetriever (ListenerRetriever 類型)負責維護兩個清單applicationListeners 和 applicationListenerBeans。Listener和Listener Bean的注冊和移除都是對這兩個清單的新增和删除。(為什麼需要Listener Bean?支援1. 非singleton bean;2. FactoryBean)

java複制代碼@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();
    }
}

@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
    synchronized (this.retrievalMutex) {
        this.defaultRetriever.applicationListeners.remove(listener);
        this.retrieverCache.clear();
    }
}           

每次事件轉發需要查詢支援該事件類型的ApplicationListener:從defaultRetriever 維護的applicationListeners和applicationListenerBeans找到适用類型的ApplicationListener對象。最後按照Order優先級排序,并傳回。

java複制代碼// 對于listenerBean來說,需要從容器中擷取對應的Bean對象
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
    ApplicationListener<?> listener =
    beanFactory.getBean(listenerBeanName, ApplicationListener.class);
    if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
        allListeners.add(listener);
    }
}           

為了避免每次查詢周遊一遍,使用retrieverCache作為緩存,這樣對于相同的事件類型,可以直接傳回對應的ApplicationListener清單。這也是為什麼每次Listener和ListenerBean新增或移除,都要清空retrieverCache。

java複制代碼protected Collection<ApplicationListener<?>> getApplicationListeners(
        ApplicationEvent event, ResolvableType eventType) {
    Object source = event.getSource();
    Class<?> sourceType = (source != null ? source.getClass() : null);
    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)))) {
        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);
    }
}           

@EventListener & EventListenerMethodProcessor

AnnotationConfigUtils給容器提供了一些預設的注解處理器。包括EventListenerMethodProcessor方法注解處理器和預設的EventListenerFactory實作。

java複制代碼// AnnotationConfigUtils#registerAnnotationConfigProcessors
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));
}           

EventListenerMethodProcessor做了以下幾件事:

  1. 從Bean容器中擷取所有EventListenerFactory接口的實作(order排序)
  2. 在容器初始化單例對象結束後,周遊所有容器中bean的類,通過反射解析出該類中@EventListener注解的方法
  3. 将這些方法通過适合的EventListenerFactory調用

createApplicationListener 包裝成ApplicationListener對象,并注冊到ApplicationContext

java複制代碼// 1. 從Bean容器中擷取所有EventListenerFactory接口的實作
@Override
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. 在容器初始化單例對象結束後,周遊所有容器中bean的類
@Override
public void afterSingletonsInstantiated() {
    ConfigurableListableBeanFactory beanFactory = this.beanFactory;
    String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
        Class<?> type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
        if (type != null) {
            processBean(beanName, type);
        }
    }
}

private void processBean(final String beanName, final Class<?> targetType) {
    if (!this.nonAnnotatedClasses.contains(targetType)) {
        // 2.1 通過反射解析出該類中@EventListener注解的方法
        Map<Method, EventListener> annotatedMethods = MethodIntrospector.selectMethods(targetType,
                (MethodIntrospector.MetadataLookup<EventListener>) method ->
                        AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
        if (CollectionUtils.isEmpty(annotatedMethods)) {
            this.nonAnnotatedClasses.add(targetType);
        }
        else {
            ConfigurableApplicationContext context = this.applicationContext;
            List<EventListenerFactory> factories = this.eventListenerFactories;
            for (Method method : annotatedMethods.keySet()) {
                for (EventListenerFactory factory : factories) {
                    // 3. 将這些方法通過适合的EventListenerFactory調用createApplicationListener
                    // 包裝成ApplicationListener對象
                    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);
                        }
                        // 3.1 注冊到ApplicationContext
                        context.addApplicationListener(applicationListener);
                        break;
                    }
                }
            }
        }
    }
}           

EventListenerFactory

DefaultEventListenerFactory是預設的EventListenerFactory實作,支援所有方法。最後将方法包裝為ApplicationListenerMethodAdapter對象。

java複制代碼public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
    @Override
    public int getOrder() {
        return 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);
    }
}           

ApplicationListenerMethodAdatper

ApplicationListenerMethodAdapter使用了擴充卡的設計模式

  1. 從方法的@EventListener注解(或方法參數)中擷取需要監聽的事件類型,以及條件表達式,從方法的@Order注解中擷取優先級資訊。
  2. supportsEventType 方法提供事件類型判斷
  3. onApplicationEvent 方法收到事件對象時:
    1. 通過方法支援的參數(是否無參)以及事件對象是否為
    2. PayloadApplicationEvent 類型解析出方法調用需要的參數資訊
    3. 根據注解的條件表達式,判斷是否可以執行方法調用
    4. 執行方法調用
    5. 将方法調用的結果作為事件對象釋出出去
java複制代碼public void processEvent(ApplicationEvent event) {
    // 通過事件對象解析方法參數
    Object[] args = resolveArguments(event);
    // 條件表達式判斷
    if (shouldHandle(event, args)) {
        // 反射執行
        Object result = doInvoke(args);
        if (result != null) {
            // 将結果作為事件釋出
            handleResult(result);
        }
    }
}           

總結

Spring Event使用ApplicationEventPublisher釋出事件,通過實作ApplicationListener監聽事件。這種模式可以解耦複雜的業務依賴。用@EventListener或@TransactionalEventListener注解處理函數,可以提供更複雜的條件過濾,或者事務狀态感覺,支援業務實作更複雜的事件處理。

從源碼實作方面,AbstractApplicationContext在refresh過程中初始化ApplicationEventMulticaster(SimpleApplicationEventMulticaster)和ApplicationListener,并向ApplicationEventMulticaster注冊監聽器。這樣在釋出事件後,ApplicationEventMulticaster能夠找到類型比對的ApplicationListener,并執行調用。

對于@EventListener或@TransactionalEventListener,則依賴方法處理器EventListenerMethodProcessor周遊所有bean并找出被注解的方法,用對應的EventListenerFactory(DefaultEventListenerFactory或者TransactionalEventListenerFactory)将該方法包裝為ApplicationListener。對于@TransactionalEventListener來說,需要額外通過事務同步器感覺事務狀态變動。

作者:喜馬Tech 晏子赢

來源-微信公衆号:喜馬拉雅技術團隊

出處:https://mp.weixin.qq.com/s/apDProsuz_E18w0FgSBrfg

繼續閱讀