本文最后更新于 946 天前,其中的信息可能已经有所发展或是发生改变。
Spring Event
Spring Event只需将事件发布出去,注册的监听器就能针对该事件执行对应的逻辑,轻松实现业务解耦。
- 定义事件
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; } } - 发布事件
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); } } - 监听事件
或者使用@EventListener注解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()); } } 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会自动搜索名称为applicationEventMulticater的ApplicationEventMulticaster实例,若实例不存在,则创建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。
- 在发布方法上添加@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); } } - 监听事件,使用@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 即使发布方法无事务,监听方法也会执行 }