Spring Boot事件监听

Spring 主要通过 ApplicationEvent 类和ApplicationListener接口提供事件处理,通过继承 ApplicationEvent 类可以实现自定义事件,实现ApplicationListener接口并注册为Bean来监听事件,详细信息可参考Spring官网文档SpringBoot官方文档

官方提示:

应用程序事件

1 实现应用程序事件监听器

import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

public class ApplicationStartingListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        System.out.println("ApplicationStartingEvent:" + event);
    }
}

2 在容器启动前注册应用程序事件监听器 

import com.example.springbootdemo.config.ApplicationStartingListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        // 方式一
//        SpringApplication application = new SpringApplication(SpringBootDemoApplication.class);
//        application.addListeners(new ApplicationStartingListener());
//        application.run(args);
        // 方式二
        new SpringApplicationBuilder(SpringBootDemoApplication.class)
                .listeners(new ApplicationStartingListener())
                .run(args);
    }
}

通常的Spring Framework事件、自定义事件及事件监听器

一、自定义事件

要实现自定义事件只需要继承ApplicationEvent 类便可。发布事件需要通过 ApplicationEventPublisher 类,可以通过 @Autowired 自动注入或实现 ApplicationEventPublisherAware 接口并注册为Bean来获取该事件发布类。

1 自定义事件实现

import org.springframework.context.ApplicationEvent;

public class TestEvent extends ApplicationEvent {

    public TestEvent(Object source) {
        super(source);
    }
}

2 自动注入获取事件发布类 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class TestEventPublisher {

    private ApplicationEventPublisher publisher;

    @Autowired
    public void setPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendTestEvent() {
        publisher.publishEvent(new TestEvent(this));
    }

}

3 实现 ApplicationEventPublisherAware 接口获取事件发布类

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

@Component
public class TestEventPublisher implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendTestEvent() {
        publisher.publishEvent(new TestEvent(this));
    }

}

二、事件监听器

方式一:通过ApplicationListener接口实现事件监听,实现ApplicationListener接口并注册为Bean

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

@Slf4j
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

方式二:通过 @EventListener 注解实现事件监听,该注解的 condition 还支持 SpEL 表达式。 

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

@Slf4j
@Component
public class EventNotifier {

    @EventListener
    public void testEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

三、异步监听器

异步监听器的实现可以依靠 @Async 注解,需要在启动类上添加 @EnableAsync 注解开启异步支持。

使用异步事件时,请注意以下限制:

  • 如果异步事件侦听器抛出Exception,则不会传播到调用者。请参阅AsyncUncaughtExceptionHandler以获取更多详细信息。

  • 异步事件侦听器方法无法通过返回值来发布后续事件。如果您需要发布另一个事件作为处理的结果,请插入一个 ApplicationEventPublisher 以手动发布事件。

1 启动类开启异步支持

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
public class SpringBootDemoApplication {

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

2 监听器实现异步 

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Async
    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class EventNotifier {

    @Async
    @EventListener
    public void testEvent(TestEvent event) {
        log.info("test event:" + event);
    }
}

四、监听器执行顺序

监听器顺序通过 @Order 指定,异步监听器不支持指定顺序。

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

@Slf4j
@Component
public class EventNotifier {

    @Order(3)
    @EventListener
    public void testEvent3(TestEvent event) {
        log.info("testEvent3:" + event);
    }

    @Order(1)
    @EventListener
    public void testEvent1(TestEvent event) {
        log.info("testEvent1:" + event);
    }

}
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Slf4j
@Order(2)
@Component
public class TestEventListener implements ApplicationListener<TestEvent> {

    @Override
    public void onApplicationEvent(TestEvent event) {
        log.info("TestEventListener:" + event);
    }
}

执行结果:

2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.springbootdemo.config.EventNotifier  : testEvent1:com.example.springbootdemo.config.TestEvent[source=com.example.springbootdemo.service.TestService@1f0dc187]
2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.s.config.TestEventListener           : TestEventListener:com.example.springbootdemo.config.TestEvent[source=com.example.springbootdemo.service.TestService@1f0dc187]
2021-02-23 23:35:35.171  INFO 29772 --- [nio-8080-exec-2] c.e.springbootdemo.config.EventNotifier  : testEvent3:com.example.springbootdemo.config.TestEvent[source=com.example.springbootdemo.service.TestService@1f0dc187]

五、通用事件

自定义通用事件类

import org.springframework.context.ApplicationEvent;

public class CommonEvent<T> extends ApplicationEvent {

    public CommonEvent(T source) {
        super(source);
    }
}

由于泛型的类型擦除,发布事件后会触发所有类型的该通用事件。所以要指定类型继承该通用事件才会精确触发监听(即 class TestServiceEvent extends CommonEvent<TestService> { …​ }),或者实现 ResolvableTypeProvider 接口。

import org.springframework.context.ApplicationEvent;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;

public class CommonEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

    public CommonEvent(T source) {
        super(source);
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章