Spring Boot:事件监听与发布


#Spring Boot#


代码中使用了 Lombok 和 Slf4j,关于这两个库的具体使用,可以参考:

示例1:Spring Boot 的生命周期中有哪些事件

在 Spring Boot 的生命周期中,会有一些事件被抛出来。我们看下如何监听这些事件。

demo01 项目结构:

demo01
├── build.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── demo
    │   │       ├── ApplicationEventListener.java
    │   │       └── Demo01Application.java
    │   └── resources
    │       └── application.properties
    └── test
        ├── java
        └── resources      

主类 Demo01Application 。

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@Slf4j
public class Demo01Application implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("...run...");
    }

    public static void main(String[] args) {
        SpringApplication.run(Demo01Application.class, args);
    }

}

事件监听类 ApplicationEventListener:

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

@Slf4j
public class ApplicationEventListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        log.info("event name: {}", event);
    }
}

application.properties 中配置监听类:

context.listener.classes=demo.ApplicationEventListener

执行主类,结果:

demo.Demo01Application                   : Starting Demo01Application on Myhost with PID 91846
demo.Demo01Application                   : No active profile set, falling back to default profiles: default
demo.ApplicationStartedEventListener            : event name: org.springframework.boot.context.event.ApplicationPreparedEvent[source=org.springframework.boot.SpringApplication@3e77a1ed]
s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2b4a2ec7: startup date [Thu Aug 02 13:12:35 CST 2018]; root of context hierarchy
o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
demo.ApplicationStartedEventListener            : event name: org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@2b4a2ec7: startup date [Thu Aug 02 13:12:35 CST 2018]; root of context hierarchy]
demo.Demo01Application                   : Started Demo01Application in 1.074 seconds (JVM running for 1.533)
demo.ApplicationStartedEventListener            : event name: org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@3e77a1ed]
demo.Demo01Application                   : ...run...
demo.ApplicationStartedEventListener            : event name: org.springframework.boot.context.event.ApplicationReadyEvent[source=org.springframework.boot.SpringApplication@3e77a1ed]
s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2b4a2ec7: startup date [Thu Aug 02 13:12:35 CST 2018]; root of context hierarchy
demo.ApplicationStartedEventListener            : event name: org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@2b4a2ec7: startup date [Thu Aug 02 13:12:35 CST 2018]; root of context hierarchy]
o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

可以看到,有 ApplicationPreparedEventContextRefreshedEventApplicationStartedEvent ApplicationReadyEventContextClosedEvent 被监听到。

示例2:通过实现 ApplicationListener 接口监听事件

示例1中已经是监听事件了。如果要监听摸一个具体的事件,该怎么做?

实现 ApplicationListener 接口,并在泛型中指定事件类型即可。

demo02 项目结构:

demo02
├── build.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── demo
    │   │       ├── ApplicationStartedEventListener.java
    │   │       └── Demo02Application.java
    │   └── resources
    └── test
        ├── java
        └── resources

注意,没有application.properties文件了。

类 ApplicationStartedEventListener :

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class ApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        log.info("{} ApplicationStartedEvent", getClass().getSimpleName());
    }
}

实现 ApplicationListener 接口,并指明要监听的事件即可。

主类 Demo02Application :

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@Slf4j
public class Demo02Application implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("...run...");
    }

    public static void main(String[] args) {
        SpringApplication.run(Demo02Application.class, args);
    }

}

执行主类:

demo.ApplicationStartedEventListener     : ApplicationStartedEventListener ApplicationStartedEvent
demo.Demo02Application                   : ...run...

示例3:使用 @EventListener 注解监听特定事件

这次使用 @EventListener 监听事件。

demo03 项目结构:

demo03
├── build.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── demo
    │   │       ├── ApplicationStartedEventListener.java
    │   │       └── Demo03Application.java
    │   └── resources
    └── test
        ├── java
        └── resources
package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class ApplicationStartedEventListener {

    @EventListener
    public void handleApplicationStartedEvent(ApplicationStartedEvent event) {
        log.info("{} ApplicationStartedEvent", getClass().getSimpleName());
    }
}

运行主类 Demo03Application :

demo.ApplicationStartedEventListener     : ApplicationStartedEventListener ApplicationStartedEvent
demo.Demo03Application                   : ...run...

demo04 - 自定义事件,并发布事件

demo04 项目结构:

demo04
├── build.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── demo
    │   │       ├── Demo04Application.java
    │   │       ├── EventHandler.java
    │   │       └── MyEvent.java
    │   └── resources
    └── test
        ├── java
        └── resources

自定义事件 MyEvent:

package demo;

public class MyEvent {

    private String msg;

    public MyEvent(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return this.msg;
    }

}

EventHandler 类 用来监听事件:

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class EventHandler {

    @EventListener
    public void handleMyEvent(MyEvent event) {
        log.info("{} handleMyEvent msg: {}", getClass().getSimpleName(), event.getMsg());
    }

}

主类 Demo04Application 在 Spring 启动后发布事件:

package demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationEventPublisher;

@SpringBootApplication
@Slf4j
public class Demo04Application implements CommandLineRunner {

    @Autowired
    public ApplicationEventPublisher publisher;

    @Override
    public void run(String... args) throws Exception {
        log.info("...run...");
        publisher.publishEvent(new MyEvent("Hello World"));
    }

    public static void main(String[] args) {
        SpringApplication.run(Demo04Application.class, args);
    }

}

运行结果:

demo.Demo04Application                   : ...run...
demo.EventHandler                        : EventHandler handleMyEvent msg: Hello World

( 本文完 )