本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

1) 监听器模式

SpringBoot 的监听器可以在程序运行中,通过捕获到感兴趣的事件而触发,从而对 ApplicationContext 或程序做一些事情。

首先先康康精简版的 SpringBoot 监听器模式,监听我们的天气事件:

1.1) 事件

public abstract class WeatherEvent {
  public abstract String getWeather();
}

public class WeatherRainEvent extends WeatherEvent {
  @Override
  public String getWeather() {
    return "Raining...";
  }
}

public class WeatherSnowEvent extends WeatherEvent {
  @Override
  public String getWeather() {
    return "Snowing...";
  }
}

1.2) 监听器

public interface WeatherListener {
  void onEvent(WeatherEvent event);
}

public class WeatherRainListener implements WeatherListener {
  @Override
  public void onEvent(WeatherEvent event) {
    if (!(event instanceof WeatherRainEvent)) return;
    System.out.println(event.getWeather());
  }
}

public class WeatherSnowListener implements WeatherListener {
  @Override
  public void onEvent(WeatherEvent event) {
    if (!(event instanceof WeatherSnowEvent)) return;
    System.out.println(event.getWeather());
  }
}

1.3) 广播器

public class WeatherBroadcast {

  private final List<WeatherListener> listeners = new ArrayList<>();

  public void broadcast(WeatherEvent event) {
    listeners.forEach(listener -> listener.onEvent(event));
  }

  public void addListener(WeatherListener listener) {
    listeners.add(listener);
  }

  public void removeListener(WeatherListener listener) {
    listeners.remove(listener);
  }
}

1.4) 测试

public class WeatherBroadcastTest {

  public static void main(String[] args) {
    WeatherRainListener weatherRainListener = new WeatherRainListener();
    WeatherSnowListener weatherSnowListener = new WeatherSnowListener();

    WeatherBroadcast weatherBroadcast = new WeatherBroadcast();
    weatherBroadcast.addListener(weatherRainListener);
    weatherBroadcast.addListener(weatherSnowListener);

    WeatherRainEvent weatherRainEvent = new WeatherRainEvent();
    WeatherSnowEvent weatherSnowEvent = new WeatherSnowEvent();
    weatherBroadcast.broadcast(weatherRainEvent);
    weatherBroadcast.broadcast(weatherSnowEvent);
  }
}

2) 定义监听器

SpringBoot 中大致可分为两类监听器,SmartApplicationListenerApplicationListener

  • SmartApplicationListener: 可实现 supportsEventType 方法实现对多种事件复杂的监听。
  • ApplicationListener: 可通过指定泛型,监听简单的单一事件。

SpringBoot 在运行中会产生下图中的事件,我们可以监听这些事件来实现我们的监听器:
SpringApplicationEvent.png

public class FirstListener implements ApplicationListener<ApplicationStartedEvent> {
  @Override
  public void onApplicationEvent(ApplicationStartedEvent event) {
    ConfigurableApplicationContext applicationContext = event.getApplicationContext();
    System.out.println("FirstListener......");
  }
}
public class SecondListener implements SmartApplicationListener {
  @Override
  public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    return eventType.isAssignableFrom(ApplicationStartedEvent.class)
        || eventType.isAssignableFrom(ApplicationFailedEvent.class);
  }

  @Override
  public void onApplicationEvent(ApplicationEvent event) {
    System.out.println("SecondListener......");
  }
}

3) 注入监听器

注入监听器的方法和注入初始化器差不多,也有三种方法

3.1) 定义 /META-INF/spring.factories 注入

如果翻阅 SpringBoot 源码会得知启动过程中会从 /META-INF/spring.factories 中取得监听器并执行,spring-boot.jar
spring-boot-autoconfigure.jar 中有此配置文件例子,我们可以参考它们的格式编写我们的 spring.factories
,放进 classpath 下的 META-INF 中:

# Application Listener, 需添加多个可用 ',' 分隔
org.springframework.context.ApplicationListener=\
cat.wars.course.multidb.listener.listener.FirstListener,\
cat.wars.course.multidb.listener.listener.SecondListener

3.2) 通过 SpringApplication 注入

通常我们的 SpringBoot 启动主函数是这样写的:

SpringApplication.run(Application.class, args);

可以拆分为两行:

SpringApplication application = new SpringApplication(Application.class);
application.run(args);

可以使用 SpringApplication.addListeners 方法添加我们的监听器

SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new FirstListener());
application.addListeners(new SecondListener());
application.run(args);

3.3) 配置文件注入

spring-boot.jar 中的 spring.factories 中定义加载了 DelegatingApplicationListener
,其中会读取配置文件中 context.listener.classes 属性,所以我们还能通过定义配置文件注入。

context:
  listener:
    classes: cat.wars.course.multidb.listener.listener.FirstListener,cat.wars.course.multidb.listener.listener.SecondListener

4) 总结

SpringBoot 中至少有三种方法,可以注入我们定义的 Spring 监听器,分别是:

  • 定义 /META-INF/spring.factories 注入
  • 通过 SpringApplicationaddListeners 方法注入
  • 通过配置文件中 context.listener.classes 属性注入