Spring Event 事件驱动
本文最后更新于 946 天前,其中的信息可能已经有所发展或是发生改变。

Spring Event

Spring Event只需将事件发布出去,注册的监听器就能针对该事件执行对应的逻辑,轻松实现业务解耦。

  1. 定义事件
    import org.springframework.context.ApplicationEvent;
    
    public class AuditEvent extends ApplicationEvent {
    
        private Object source;
        public int status;
        private String message;
    
        public AuditEvent(Object source, int status, String message) {
            super(source);
            this.source = source;
            this.message = message;
        }
    
        public int getStatus() {
            return status;
        }
    
        public String getMessage() {
            return message;
        }
    }
  2. 发布事件
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class AuditService {
    
        @Resource
        private ApplicationEventPublisher eventPublisher;
    
        public void audit() {
            AuditEvent auditEvent = new AuditEvent(this, 1, "审核中");
            eventPublisher.publishEvent(auditEvent);
        }
    }
  3. 监听事件
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    @Slf4j
    @Component
    public class AuditEventListener implements ApplicationListener {
        @Override
        public void onApplicationEvent(AuditEvent event) {
            log.info(event.getMessage());
        }
    }
    或者使用@EventListener注解
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    @Slf4j
    @Component
    public class AuditEventProcessor {
        @EventListener(classes = AuditEvent.class)
        public void processor(AuditEvent event) {
            log.info(event.getMessage());
        }
    }

异步执行

Spring会自动搜索名称为applicationEventMulticaterApplicationEventMulticaster实例,若实例不存在,则创建SimpleApplicationEventMulticaster作为事件转发处理器,默认是同步执行(发布和接收事件都使用同一线程)。我们可以自定义Executor来替换默认行为。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import java.util.concurrent.*;
@Configuration
public class AsyncExecutor {
    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        //自定义Executor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        eventMulticaster.setTaskExecutor(threadPoolExecutor);
        return eventMulticaster;
    }
}

不过若如此,会导致所有的监听器都是异步执行,解决方案如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Slf4j
@Component
public class AuditEventProcessor {
    private Executor executor = Executors.newSingleThreadExecutor();
    @EventListener(classes = AuditEvent.class)
    public void processor(AuditEvent event) {
        executor.execute(() -> log.info(event.getMessage()));
    }
}

更优雅的方案是使用@Async注解,如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AuditEventProcessor {
    @Async //记得在启动类上声明@EnableAsync注解开启异步支持
    @EventListener(classes = AuditEvent.class)
    public void processor(AuditEvent event) {
        log.info(event.getMessage());
    }
}

@TransactionalEventListener

业务有时候希望事件的发布能与事务进行绑定,比如在事务提交后发送Event。@TransactionEventListener允许监听方法能够感知事务,使用phase属性,声明事务在哪个阶段发送Event。

  1. 在发布方法上添加@Transactional注解
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.support.TransactionSynchronizationManager;
    
    import javax.annotation.Resource;
    
    @Service
    public class AuditService {
    
        @Resource
        private ApplicationEventPublisher eventPublisher;
    
        @Transactional
        public void audit() {
            //判断当前线程是否在事务方法中
            boolean actualTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
            System.err.println(actualTransactionActive);
            //获取当前事务名
            String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
            System.err.println(currentTransactionName);
            
            AuditEvent auditEvent = new AuditEvent(this, 1, "审核中");
            eventPublisher.publishEvent(auditEvent);
        }
    }
  2. 监听事件,使用@TransactionalEventListener注解
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.event.TransactionPhase;
    import org.springframework.transaction.event.TransactionalEventListener;
    
    @Slf4j
    @Component
    public class AuditEventProcessor {
    
        //此处监听方法和发布方法使用同一事务,若想监听方法使用新事务,可解开如下注释
        //@Transactional(propagation = Propagation.REQUIRES_NEW)
        @TransactionalEventListener(classes = AuditEvent.class, phase = TransactionPhase.BEFORE_COMMIT, fallbackExecution = true)
        public void processor(AuditEvent event) {
            //判断当前线程是否在事务方法中
            boolean actualTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
            System.err.println(actualTransactionActive);
            //获取当前事务名
            String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
            System.err.println(currentTransactionName);
            
            log.info(event.getMessage());
        }
        
        //phase属性
        //BEFORE_COMMIT		事务提交之前触发事件,此时事务还存在,监听方法和发布方法使用同一事务
        //AFTER_COMMIT		事务提交之后触发事件,此时事务已结束,监听方法和发布方法使用不同事务
        //AFTER_ROLLBACK	事务回滚之后触发事件
        //AFTER_COMPLETION	事务完成之后触发事件,类似AFTER_COMMIT和AFTER_ROLLBACK的结合
        
        //fallbackExecution属性
        //false	发布方法无事务,监听方法不会执行
        //true	即使发布方法无事务,监听方法也会执行
    }
如果觉得本文对您有帮助,记得收藏哦~
上一篇
下一篇