专栏首页小灰灰【SpringBoot 基础系列】事件机制的两种消费姿势

【SpringBoot 基础系列】事件机制的两种消费姿势

I. 项目环境

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

为了后面的发布事件验证,起一个web服务

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

II. 事件机制

1. 事件对象

在Spring中,所有的事件需要继承自ApplicationEvent,一个最基础的MsgEvent如下

public class MsgEvent extends ApplicationEvent {
    private String msg;

    /**
     * Create a new {@code ApplicationEvent}.
     *
     * @param source the object on which the event initially occurred or with
     *               which the event is associated (never {@code null})
     */
    public MsgEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MsgEvent{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

2. 接口方式消费

消费事件有两种方式,接口的声明,主要是实现ApplicationListener接口;注意需要将listener声明为Spring的bean对象

@Service
public class MsgEventListener implements ApplicationListener<MsgEvent> {
    @Override
    public void onApplicationEvent(MsgEvent event) {
        System.out.println("receive msg event: " + event);
    }
}

3. 注解方式消费

实现接口需要新建实现类,更简单的方法是直接在消费方法上加一个注解@EventListener

@EventListener(MsgEvent.class)
public void consumer(MsgEvent msgEvent) {
    System.out.println("receive msg by @anno: " + msgEvent);
}

这个注解,支持根据Event参数类型进行匹配,即上面的实例中,方法上直接加@EventListener不指定圆括号内部的也没关系

4. 发布事件

前面是消费事件,消费的前提是有事件产生,在Spring中,发布事件主要需要借助ApplicationContext来实现

@Service
public class MsgPublisher implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void publish(String msg) {
        applicationContext.publishEvent(new MsgEvent(this, msg));
    }
}

5. 测试

一个简单的测试demo

@RestController
public class IndexController {
    @Autowired
    private MsgPublisher msgPublisher;

    @GetMapping(path = "pub")
    public String publish(String msg) {
        msgPublisher.publish(msg);
        return "ok";
    }
}

访问: curl http://localhost:8082/pub?msg=一灰灰blog

输出日志:

receive msg by @anno: MsgEvent{msg='一灰灰blog'}
receive msg event: MsgEvent{msg='一灰灰blog'}

上面这个测试两种消费方式都可以成功,但是,在实测的过程中发现一种case,注解消费方式不生效,测试姿势如下

@SpringBootApplication
public class Application {

    public Application(MsgPublisher msgPublisher) {
        msgPublisher.publish("一灰灰blog");
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

}

直接在启动类的构造方法中发布事件,发现接口方式可以接收事件,但是注解方式不生效,why?

在stockoverstack上有个相似的问题 https://stackoverflow.com/questions/38487474/springboot-eventlistener-dont-receive-events,这里主要提了一个观点

  • 发布消息比事件消费注册的要早

那么是这个原因么? 静待下次源码分析

II. 其他

0. 项目

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【SpringBoot 基础系列】事件机制的两种消费姿势

    借助Spring可以非常简单的实现事件监听机制,本文简单介绍下面向接口与注解监听的两种姿势

    一灰灰blog
  • 【SpringBoot MQ 系列】RabbitMq 消息发送基本使用姿势

    前面两篇博文,分别介绍了RabbitMq的核心知识点,以及整合SpringBoot的demo应用;接下来也该进入正题,看一下SpringBoot的环境下,如何玩...

    一灰灰blog
  • 【SpringBoot DB 系列】Redis 高级特性之发布订阅

    通常来讲,当我们业务存在消息的业务逻辑时更多的是直接使用成熟的 rabbitmq,rocketmq,但是一些简单的业务场景中,真的有必要额外的引入一个 mq 么...

    一灰灰blog
  • 【SpringBoot DB 系列】Redis 高级特性之发布订阅

    通常来讲,当我们业务存在消息的业务逻辑时更多的是直接使用成熟的 rabbitmq,rocketmq,但是一些简单的业务场景中,真的有必要额外的引入一个 mq 么...

    一灰灰blog
  • 【SpringBoot MQ 系列】RabbitListener 消费基本使用姿势介绍

    之前介绍了 rabbitmq 的消息发送姿势,既然有发送,当然就得有消费者,在 SpringBoot 环境下,消费可以说比较简单了,借助@RabbitListe...

    一灰灰blog
  • SpringBoot基础系列@Value 之字面量及 SpEL使用知识点介绍篇

    承接上一篇博文【SpringBoot 基础系列】@Value 中哪些你不知道的知识点 中提及到但没有细说的知识点,这一篇博文将来看一下@Value除了绑定配置文...

    一灰灰blog
  • SpringBoot基础系列@Value 之字面量及 SpEL使用知识点介绍篇

    承接上一篇博文[【SpringBoot 基础系列】@Value 中哪些你不知道的知识点](http://mp.weixin.qq.com/s?__biz=MzU...

    一灰灰blog
  • SpringBoot系列教程JPA之update使用姿势

    上面两篇博文拉开了jpa使用姿势的面纱一角,接下来我们继续往下扯,数据插入db之后,并不是说就一层不变了,就好比我在银行开了户,当然是准备往里面存钱了,有存就有...

    一灰灰blog
  • SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势

    虽然 http 的提供了一整套完整、定义明确的状态码,但实际的业务支持中,后端并不总会遵守这套规则,更多的是在返回结果中,加一个 code 字段来自定义业务状态...

    一灰灰blog

扫码关注云+社区

领取腾讯云代金券