Skip to main content

SpringEvent事件监听解耦


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 可以配置事务阶段,例如 beforeCommitafterCommitafterRollbackafterCompletion。这允许您精确地控制事件处理器在事务生命周期的哪个阶段执行。
  • EventListener 不提供类似的配置选项,它简单地监听事件并在触发时执行相应的逻辑。