1. 在众多的Spring教学视频中,很少有课程去讲解SpringEvent相关功能使用的。或许是比较简单吧。引发对Event功能探究的原因是最近在看PIG开源项目,发现其中认证模块多处使用到了SpringEvent的功能。于是,准备翻翻官方文档做一个学习笔记。

1.简介

ApplictionContext中的事件发布和处理的操作,是由ApplictionEventApplictionListener两个接口来实现的。当一个Bean实现了ApplictionListener并加入了容器。当一个ApplictionEvent发布到容器后,这个Bean就可以自动地获取到这个Event并进行处理。这是典型的观察者模式(Observer Pattern)
对于ApplictionEvent,Spring框架帮我们内置了好多:

  • ContextRefreshedEvent
  • ContextStartedEvent
  • ContextStoppedEvent

2.自定义事件发布和获取

2.1自定义一个事件

  • 类extends ApplicationEvent

官方实例:

  1. @Data
  2. public class BlockedListEvent extends ApplicationEvent {
  3. private final String address;
  4. private final String content;
  5. public BlockedListEvent(Object source, String address, String content) {
  6. super(source);
  7. this.address = address;
  8. this.content = content;
  9. }
  10. // accessor and other methods...
  11. }

2.2创建事件发布者

事件的发布需要使用Spring提供的ApplicationEventPublisher来发布。或者通过ApplicationContext也可以发布

  1. @Component
  2. public class EmailService implements ApplicationEventPublisherAware {
  3. private ApplicationEventPublisher publisher;
  4. @Override
  5. public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
  6. this.publisher = publisher;
  7. }
  8. public void sendEmail(String address, String content) {
  9. //发布事件
  10. publisher.publishEvent(new BlockedListEvent(this, address, content));
  11. }
  12. }

2.3创建监听者

监听者可以获取到事件对象。具体的实现方式如下:

  1. @Component
  2. public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
  3. private String notificationAddress;
  4. public void setNotificationAddress(String notificationAddress) {
  5. this.notificationAddress = notificationAddress;
  6. }
  7. @SneakyThrows
  8. @Override
  9. public void onApplicationEvent(BlockedListEvent event) {
  10. System.err.println("接收消息");
  11. Thread.sleep(5000);
  12. System.out.println(event);
  13. // notify appropriate parties via notificationAddress...
  14. }
  15. }

2.4注意事项

  • 同一类Event,在上一个没有处理完成时。永远不允许发送第二个
  • 监听者的消费顺序是一个一个来的,不是并发
  • 监听者都可以拿到消息

    3.使用注解方式注册监听器

    在前面我们注册一个监听者需要写一个类,如果要监听多个事件就要有多个类对象,但是大多数情况下可能逻辑就是记录个日志,所以注解方式可以实现一个Bean写多个方法处理不同的事件。每个方法处理一类或多类事件。 @EventListener ```java @Component public class MyListener { @EventListener public void commence(BlockedListEvent event){ System.err.println(“注解方式处理”); System.err.println(event);

    }

}

  1. 此外注解里值还可以对事件进行过滤和处理完后也发事件。具体内容用到时再仔细看一下。具体功能有:
  2. 1. 通过事件对象中的字段过滤
  3. 2. 处理完事件后,也发布一个事件
  4. <a name="xpfTz"></a>
  5. # 4.异步监听器
  6. 异步监听器没啥特别的,就是在方法上添加一个`@Async`注解
  7. ```java
  8. @EventListener
  9. @Async
  10. public void processBlockedListEvent(BlockedListEvent event) {
  11. // BlockedListEvent is processed in a separate thread
  12. }

5.顺序监听器

不用说吧,@Order注解来解决

  1. @EventListener
  2. @Order(42)
  3. public void processBlockedListEvent(BlockedListEvent event) {
  4. // notify appropriate parties via notificationAddress...
  5. }

6.通用事件类型

在2节中,我们通过实现ApplicationEvent来定义自己的事件,但是其实我们的事件可能就是我们的一个实体类。于是乎,Spring提供了一个EntityCreatedEvent<T>。T就是指定我们自己定义的实体类即可。
注:这个功能我没有实验出来,因为我没有这个类。不知道为啥。