SpringEvent事件监听解耦
About 3 min
SpringEvent事件监听
当用户注册的时候,我们希望取监听这个事件做一些事情,例如用户注册就去给他发送一张改名卡
我们可以使用监听者模式:
@Override
@Transactional
public Long register(User registerUser) {
boolean save = save(registerUser);
// 用户注册的事件
applicationEventPublisher.publishEvent(new UserRegisterEvent(this, registerUser));
return save ? registerUser.getId() : null;
}
在用户注册的时候,去applicationEventPublisher.publishEvent(new UserRegisterEvent(this, registerUser));
订阅这个事件,其实 这个就是装饰者模式,因为publishEvent原本要传的是
default void publishEvent(ApplicationEvent event) { publishEvent((Object) event); }
我们现在写一个自己的来对这个对象进行增强,使得可以将用户传入
@Getter
public class UserRegisterEvent extends ApplicationEvent {
private User user;
public UserRegisterEvent(Object source, User user) {
super(source);
this.user = user;
}
}
然后再去监听这个 :
@Component
public class UserRegisterListener {
@Resource
private UserBackpackService userBackpackService;
@Resource
private UserService userService;
@Async
@EventListener(classes = UserRegisterEvent.class)
public void sendCard(UserRegisterEvent event) throws InterruptedException {
// 注册事件监听,送一张改名卡
User user = event.getUser();
userBackpackService.acquireItem(user.getId(), ItemEnum.MODIFY_NAME_CARD.getId(), IdempotentEnum.UID, user.getId().toString());
}
@Async
@EventListener(classes = UserRegisterEvent.class)
public void sendBadge(UserRegisterEvent event) throws InterruptedException {
User user = event.getUser();
int count = userService.count();// 性能瓶颈,等注册用户多了直接删掉
if (count <= 10) {
userBackpackService.acquireItem(user.getId(), ItemEnum.REG_TOP10_BADGE.getId(), IdempotentEnum.UID, user.getId().toString());
} else if (count <= 100) {
userBackpackService.acquireItem(user.getId(), ItemEnum.REG_TOP100_BADGE.getId(), IdempotentEnum.UID, user.getId().toString());
}
}
}
- 这里我们使用了
@Async
,这样的话,这个任务就是异步执行的了 ,可以提高效率 @EventListener(classes = UserRegisterEvent.class)
表示监听UserRegisterEvent.class
这个类
我们不仅给每个注册用户赠送改名卡,而且还给前10名注册用户赠送徽章,给100名注册用户赠送徽章,可以在一个监听器里面完成,者也是实现了解耦合。
还要注意的是,这个 监听器的执行成功我们需要考虑,这个赠送到底重要不重要
如果没有赠送成功,那么可以影响到我们注册事件的正常执行吗?
没有赠送成功,就注册失败了?
这就需要看自己的想法了。
我们觉得用户注册一定要成功,改名卡可以失败
在注册这边加事务
@Transactional
public Long register(User registerUser) {
将监听器的事物设置为提交之后:
也就是事务提交后,才会去执行,不会影响注册的事务
@TransactionalEventListener(classes = UserRegisterEvent.class,phase = TransactionPhase.AFTER_COMMIT)
public void sendCard(UserRegisterEvent event) throws InterruptedException {
这两个注解的区别 :
执行时机:
TransactionalEventListener
是与事务相关的事件监听器。它只会在事务成功提交后触发,如果事务回滚,则事件不会被触发。这意味着事件处理器只在事务成功提交后才会执行,从而确保在一致的事务上下文中处理事件。EventListener
则是非事务性的事件监听器,不与事务相关。它可以在任何时候触发,无论事务是否成功提交或回滚。配置选项:
TransactionalEventListener
可以配置事务阶段,例如beforeCommit
、afterCommit
、afterRollback
和afterCompletion
。这允许您精确地控制事件处理器在事务生命周期的哪个阶段执行。EventListener
不提供类似的配置选项,它简单地监听事件并在触发时执行相应的逻辑。