关于java:SpringBoot-基础系列事件机制的两种消费姿势

借助Spring能够非常简单的实现事件监听机制,本文简略介绍上面向接口与注解监听的两种姿态

【SpringBoot 根底系列】事件机制的两种生产姿态

<!– more –>

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. 我的项目

  • 工程:https://github.com/liuyueyi/spring-boot-demo
  • 源码:https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/012-context-listener/

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因集体能力无限,不免有疏漏和谬误之处,如发现bug或者有更好的倡议,欢送批评指正,不吝感谢

上面一灰灰的集体博客,记录所有学习和工作中的博文,欢送大家前去逛逛

  • 一灰灰Blog集体博客 https://blog.hhui.top
  • 一灰灰Blog-Spring专题博客 http://spring.hhui.top
  • 微信公众号: 一灰灰blog

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理