实现方法
- 自定义需要发布的事件类,需要继承
ApplicationEvent
类或PayloadApplicationEvent<T>
(该类也仅仅是对ApplicationEvent的一层封装) - 使用
@EventListener
来监听事件 - 使用
ApplicationEventPublisher
来发布自定义事件(@Autowired
注入即可)
/**
* 自定义保存事件
* @author peter
* 2019/1/27 14:59
*/
public class PersonSaveEvent<DATA> extends ApplicationEvent {
private DATA data;
public PersonSaveEvent(DATA source) {
super(source);
this.data = source;
}
public DATA getData() {
return data;
}
}
//发布事件
public void savePerson(Person person){
personDao.save(person);
publisher.publishEvent(new PersonSaveEvent<>(1));
}
//监听事件
@EventListener
public void listenEvent(PersonSaveEvent<Integer> event) {
System.out.println("监听到PersonSaveEvent事件; 接收到的值:" + event.getData() + ";发布的时间为" + Instant.ofEpochMilli(event.getTimestamp()));
}
好处
可以使核心业务与子业务进行解耦,也方便后期的业务的扩展。如新用户注册之后,需要发放优惠券,此时可以在保存用户之后,发布一个新用户的注册成功事件
,通过监听该事件来实现发放优惠券的功能。后期新增一个对新用户进行xxx功能,此时可以新写一个监听注册成功事件
的监听器,来处理新的业务逻辑,而不需要修改之前的注册逻辑。
注意事项
1、监听器方法中一定要try-catch异常,否则会造成发布事件(有事务的)的方法进行回滚
2、可以使用@Order注解来控制多个监听器的执行顺序,@Order传入的值越小,执行顺序越高
3、对于需要进行s事务监听或不想try-catch runtime异常,可以使用@TransactionalEventListener注解
@TransactionalEventListener 监听器
在该注解的源码中:
* <p>If the event is not published within the boundaries of a managed transaction, the
* event is discarded unless the {@link #fallbackExecution} flag is explicitly set. If a
* transaction is running, the event is processed according to its {@code TransactionPhase}.
大意是:如果事件的发布不是在事务(@Transactional
)范围内,则监听不到该事件,除非将fallbackExecution标志设置为true(@TransactionalEventListener(fallbackExecution = true)
);如果在事务中,可以选择在事务的哪个阶段来监听事件,默认在事务提交后监听。
修改监听事务的范围:@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
在监听器中重新开一个事务
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void listenEvent1(PersonSaveEvent<Integer> event) {
divide(event);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void divide(PersonSaveEvent<Integer> event) {
System.out.println("监听到PersonSaveEvent事件; 接收到的值:" + event.getData() + ";接受的时间为" + Instant.ofEpochMilli(event.getTimestamp()));
}
以上事件都是同步,如果需要异步则需要开启异步支持,在监听器方法加上@Async
注解即可。
/**
* 开启异步支持
* @author peter
* @version 1.0
* @date 2019/04/18 08:47
*/
@Configuration
@EnableAsync
public class AsyncEventConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newCachedThreadPool();
}
}
一旦开始异步执行,方法的异常将不会抛出,只能在方法内部处理。如需在方法外处理异常:Async 异常处理在文章最后