业务解耦工具:Spring Event用法和源码分析

176 阅读10分钟

Spring Event

使用Spring Event,可以轻松实现业务解耦。只需要将事件发布出去,注册的监听器可以针对这个事件执行对应的业务逻辑。适用于同一个应用内的事件监听。比如审核通过,需要初始化下一个流程相关业务逻辑、给用户发送通知消息、写入变更历史表、发送消息到消息队列等。

定义事件

继承ApplicationEvent,将需要传递的事件信息包装为业务事件类,如下所示。

public class AuditEvent extends ApplicationEvent {
    private Object source;
    private int auditStatus;  // 审核状态
    private long auditId;  // 审核ID

    public AuditEvent(Object source, int auditStatus, long auditId) {
        super(source);
        this.auditStatus = auditStatus;
        this.auditId = auditId;
    }
    // getter
}

事件发布

注入ApplicationEventPublisher,通过publishEvent方法即可发布事件。ApplicationEventPublisher的一般实现是AbstractApplicationContext,即Spring容器本身就是可以发送Spring事件。

@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方法。通过泛型指定需要监听的事件类。

@Component
public class AuditEventListener implements ApplicationListener<AuditEvent> {

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

@EventListener

也可以使用@EventListener注解方法,将其包装为事件处理器。它适用于:1. 不想为每个事件处理都创建一个ApplicationListener实现类;2. 希望支持更复杂的事件条件过滤。@EventListener的classes属性可以过滤事件类型,而condition属性可以根据事件对象是否满足条件表达式来过滤事件。

@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,以此来支持异步执行。

@Configuration
public class Config {

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

不过这样设置之后,所有Listener都是异步执行。对于需要同时支持异步和同步执行的应用,考虑下面的方案。

  1. 手动提交线程池异步执行

适用于简单的场景。但这样对代码的侵入性比较高,

private Executor executor = Executors.newFixedThreadPool(1);

public void onApplicationEvent(CustomEvent event) {
    executor.execute(() -> process(event));
}
  1. 使用@Async 注解

对于@EventListener注解的方法处理器,可以使用@Async注解,使得方法调用变为异步调用。(需要在启动类Application上使用@EnableAsync注解,引入对@Async的支持。)

感知事务 @TransactionalEventListener

业务可能并不希望事件在发布的时候就立马执行,而是与事务的某个阶段进行绑定。比如在事务提交之后(出错的概率比较低),发送短信通知用户。@TransactionEventListener允许事件处理方法感知事务。它的phase属性,表示希望在事务的哪个阶段执行事件处理。

如下所示,当在事务环境下(@Transactional 注解),发送事件时,如果使用TransactionalEventListener监听事件,那么默认情况下会延迟到事务已提交之后才开始执行。这样避免在后续操作出错、导致事务回滚的情况下,事件已经被处理,无法撤回。

@Service
public class AuditService {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    // 事务环境
    @Transactional
    public void audit(int auditStatus, long auditId) {
        // 修改数据库审核状态
        auditMapper.updateStatusById(auditStatus, auditId);
        // 发送审核事件
        applicationEventPublisher.publishEvent(new AuditEvent(this, auditStatus, auditId));
        // 做一些其他操作
    }
}

@Component
public class EventProcessor {

    @TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT)
    public void whenCommit(CustomEvent event) {
        // 只在事务已提交后,触发事件
    }

    @TransactionalEventListener(phase=TransactionPhase.AFTER_ROLLBACK)
    public void whenRollback(CustomEvent event) {
        // 只在事务回滚的情况下,触发事件
    }
}

源码分析:事件发布与转发

ApplicationEventMulticaster.png

ApplicationEventPublisher

Spring容器(父类AbstractApplicationContext)把自身作为ApplicationEventPublisher类的实现注册到容器中

// AbstractApplicationContext#prepareBeanFactory
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

AbstractApplicationContext作为ApplicationEventPublisher,实现了publishEvent方法,将其转发给内部实现:

  1. 包装非ApplicationEvent对象为PayloadApplicationEvent
  2. 在Listener初始化之前保存早期发布的事件
  3. 在初始化之后直接给交给applicationEventMulticaster发布事件
  4. 同时将事件发布给父容器(如果有,且是AbstractApplicationContext实现)
// 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。

// AbstractApplicationContext
public void refresh() {
    prepareRefresh();
    ...
    initApplicationEventMulticaster();
    onRefresh();
    registerListeners(); // 注册监听器
    ...
}

如果容器中已经注册有名为applicationEventMulticaster的Bean,则使用它(我们可以通过这种方式注册自定义的ApplicationEventMulticaster,比如添加线程处理器),否则默认使用SimpleApplicationEventMulticaster作为转发器。

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。同时开始转发早期收集的事件。

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

关于earlyApplicationEvents

AbstractApplicationContext的refresh()方法确定了容器初始化的流程,在prepareRefresh()中将earlyApplicationEvents初始化为空列表,再此之后初始化过程中发送的事件,都将保存在earlyApplicationEvents中。而后续先初始化applicationEventMulticaster,再注册完监听器,此时会将earlyApplicationEvents中所有事件发送给监听器,然后置为null,至此earlyApplicationEvents的任务就已经完成了。

SimpleApplicationEventMulticaster

SimpleApplicationEventMulticaster 继承自AbstractApplicationEventMulticaster ,后者实现了Listener和Listener Bean注册和移除、查找,前者在此基础上,实现了事件转发的功能。在multicastEvent方法中,遍历所有支持该事件类型的ApplicationListener,调用其onApplicationEvent方法。SimpleApplicationEventMulticaster 允许用户设置Executor,使用Executor执行事件处理程序。

// 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)

@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优先级排序,并返回。

// 对于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。

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.png

EventListenerMethodProcessor

AnnotationConfigUtils给容器提供了一些默认的注解处理器。包括EventListenerMethodProcessor方法注解处理器和默认的EventListenerFactory实现。

// 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
// 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对象。

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 方法收到事件对象时:
    • 通过方法支持的参数(是否无参)以及事件对象是否为PayloadApplicationEvent 类型解析出方法调用需要的参数信息
    • 根据注解的条件表达式,判断是否可以执行方法调用
    • 执行方法调用
    • 将方法调用的结果作为事件对象发布出去
public void processEvent(ApplicationEvent event) {
    // 通过事件对象解析方法参数
    Object[] args = resolveArguments(event);
    // 条件表达式判断
    if (shouldHandle(event, args)) {
        // 反射执行
        Object result = doInvoke(args);
        if (result != null) {
            // 将结果作为事件发布
            handleResult(result);
        }
    }
}

源码分析:@TransactionalEventListener

TransactionalEventListenerFactory

TransactionalEventListenerFactory优先将被@TransactionalEventListener注解的方法包装为感知事务的ApplicationListener。

public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {

    private int order = 50;  // 优先级比DefaultEventListenerFactory高

    @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 ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
    }

}

ApplicationListenerMethodTransactionalAdapter

继承自ApplicationListenerMethodAdapter,提供了基础的事件类型解析和方法调用逻辑。但它依赖当前环境中是否有事务,通过注册事务同步器,在事务状态转移的时候执行相应的回调任务。这样能够将事件处理和某些事务状态进行绑定执行。

class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter {

    private final TransactionalEventListener annotation;

    public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
        super(beanName, targetClass, method);
        TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
        this.annotation = ann;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        // 事务处于开启状态
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            // 注册事务同步器,在事务状态转移的时候执行相应的回调任务
            TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
            TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
        }
        else if (this.annotation.fallbackExecution()) {
            // fallbackExecution为true,表明没有事务的时候也执行
            processEvent(event);
        }
        else {
            // fallbackExecution为false,没有事务,不处理
        }
    }

    private TransactionSynchronization createTransactionSynchronization(ApplicationEvent event) {
        return new TransactionSynchronizationEventAdapter(this, event, this.annotation.phase());
    }

    // 事务同步器,它会在事务状态变动时触发回调
    private static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter {

        private final ApplicationListenerMethodAdapter listener;
        private final ApplicationEvent event;
        private final TransactionPhase phase;

        public TransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter listener,
                ApplicationEvent event, TransactionPhase phase) {
            this.listener = listener;
            this.event = event;
            this.phase = phase;
        }

        @Override
        public int getOrder() {
            return this.listener.getOrder();
        }

        @Override
        public void beforeCommit(boolean readOnly) {
            if (this.phase == TransactionPhase.BEFORE_COMMIT) {
                processEvent();
            }
        }

        @Override
        public void afterCompletion(int status) {
            if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {
                processEvent();
            }
            else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) {
                processEvent();
            }
            else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
                processEvent();
            }
        }

        protected void processEvent() {
            this.listener.processEvent(this.event);
        }
    }
}

总结

Spring Event使用ApplicationEventPublisher发布事件,通过实现ApplicationListener监听事件。这种模式可以解耦复杂的业务依赖。用@EventListener或@TransactionalEventListener注解处理函数,可以提供更复杂的条件过滤,或者事务状态感知,支持业务实现更复杂的事件处理。

从源码实现方面,AbstractApplicationContext在refresh过程中初始化ApplicationEventMulticaster(SimpleApplicationEventMulticaster)和ApplicationListener,并向ApplicationEventMulticaster注册监听器。这样在发布事件后,ApplicationEventMulticaster能够找到类型匹配的ApplicationListener,并执行调用。

对于@EventListener或@TransactionalEventListener,则依赖方法处理器EventListenerMethodProcessor遍历所有bean并找出被注解的方法,用对应的EventListenerFactory(DefaultEventListenerFactory或者TransactionalEventListenerFactory)将该方法包装为ApplicationListener。对于@TransactionalEventListener来说,需要额外通过事务同步器感知事务状态变动。