前段时间看到同事在项目里面使用了一个叫做 @EventLintener 的注解。

在这之前,我知道这个注解的用法和想要达到的目的,但是也仅限于此,其内部工作原理对我来说是一个黑盒,我完完全全不知道它怎么就实现了“监听”的效果。

现在既然已经出现在项目里面了,投入上生产上去使用了,所以我打算盘一下它,以免以后碰到问题的时候错过一个装逼的...

哦,不。

错过一个表现自己的机会。

Demo

首先,按照歪歪歪师傅的老规矩,第一步啥也别说,先搞一个 Demo 出来,没有 Demo 的源码解读,就像是吃面的时候没有大蒜,差点意思。

先铺垫一个背景吧。

假设现在的需求是用户注册成功之后给他发个短信,通知他一下。

正常来说,伪代码很简单:

boolean success = userRegister(user); if(success){
    sendMsg("客官,你注册成功了哦。记得来玩儿~");
} 

这代码能用,完全没有任何问题。但是,你仔细想,发短信通知这个动作按理来说,不应该和用户注册的行为“耦合”在一起,难道你短信发送的时候失败了,用户就不算注册成功吗?

上面的代码就是一个耦合性很强的代码。

怎么解耦呢?

应该是在用户注册成功之后,发布一个“有用户注册成功了”的事件:

boolean success = userRegister(user); if(success){
    publicRegisterSuccessEvent(user);
} 

然后有地方去监听这个事件,在监听事件的地方触发“短信发送”的动作。

这样的好处是后续假设不发短信了,要求发邮件,或者短信、邮件都要发送,诸如此类的需求变化,我们的用户注册流程的代码不需要进行任何变化,仅仅是在事件监听的地方搞事情就完事了。

这样就算是完成了两个动作的“解耦”。

怎么做呢?

我们可以基于 Spring 提供的 ApplicationListener 去做这个时间。

我的 Demo 里面用的 Spring 版本是 5.2.10。

这次的 Demo 也非常的简单,我们首先需要一个对象来封装事件相关的信息,比如我这里用户注册成功,肯定要关心的是 userName:

@Data
public class RegisterSuccessEvent {

    private String userName;

    public RegisterSuccessEvent(String userName) {
        this.userName = userName;
    }
} 

我这里只是为了做 Demo,对象很简单,实际使用过程中,你需要什么字段就放进去就行。

然后需要一个事件的监听逻辑:

@Slf4j
@Component
public class RegisterEventListener {

    @EventListener
    public void handleNotifyEvent(RegisterSuccessEvent event) {
        log.info("监听到用户注册成功事件:" +
                "{},你注册成功了哦。记得来玩儿~", event.getUserName());
    }

} 

接着,通过 Http 接口来进行事件发布:

@Resource
private ApplicationContext applicationContext;
@GetMapping("/publishEvent")
public void publishEvent() {
    applicationContext.publishEvent(new RegisterSuccessEvent("歪歪"));
} 

最后把服务启动起来,调用一次:


输出正常,完事儿,这个 Demo 就算是搞定了,就只有十多行代码。

这么简单的 Demo 你都不想亲自动手去搭一个的话,想要靠肉眼学习的话,那么我只能说: