0、前提
本文分析springboot中的listener只是简单的分析下,关键部分的地方都给了注释的,其余有些细节的地方并没有去分析,感兴趣的读者可以自行去分析下。(其实是懒!逃......)
如果还不了解观察者设计模式的,可以看看这篇文章:springboot 源码解析(一)ApplicationListener
1、springboot Listener
1.1 自定义listener
可以实现
GenericApplicationListener
接口,GenericApplicationListener继承自ApplicationListener,ApplicationListener接口里面只有一个onApplicationEvent()方法,GenericApplicationListener接口里面提供了其余的几个方法,GenericApplicationListener接口相当于对其父类进行了增强,使listener订阅事件的方式增加。// supportsEventType()和supportsSourceType()方法必须同时返回true才代表对这个事件感兴趣 // 这个类有三个地方可以对事件进行订阅 public class MyListener implements GenericApplicationListener { // (1)这里也可以对事件进行订阅,对自己感兴趣的事件执行相关逻辑 public void onApplicationEvent(ApplicationEvent event) { System.out.println("-----------myListener"); } // (2)表示你对什么时间感兴趣,直接返回true代表对所有的事件都感兴趣, // 可以通过参数 eventType来设置自己感兴趣的。简单来说就是订阅事件 public boolean supportsEventType(ResolvableType eventType) { return true; } // (2)直接返回true表示对所有的事件都感兴趣 // 可以通过相关逻辑设置对感兴趣的事件源进行订阅 public boolean supportsSourceType(Class<?> sourceType) { return true; } // 数字越小,越先执行 public int getOrder() { return 0; } }
resources目录下创建文件
spring.factories
# Application Listeners org.springframework.context.ApplicationListener=\ com.demo.listener.MyListener
1.2 Listener源码解析
App.java
public class App { public static void main(String[] args) { // SpringApplication.run(App.class); // 这里的构造方法里面得到了所有的listener SpringApplication application = new SpringApplication(App.class); application.run(args); } }
SpringApplication.java
SpringApplication的构造方法,里面得到所有的listener
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 一般传过来的 resourceLoader参数为空 this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推断 webApplicationType 的类型(比如servlet项目、普通java项目),这里很重要 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // springboot最核心的地方。 // 从 spring.factories 配置文件中定义的 ApplicationContextInitializer 类对应的value值保存到 initializers(List)集合中 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 所有的listener都在这进行实例化了 // spring.factories 配置文件中定义的 ApplicationListener 类对应的value值保存到 listeners(List)集合中 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 推断启动类 // 通过抛一个运行时异常,拿到所有的栈帧,从这里拿到 main()方法所在的主类。真流弊!! this.mainApplicationClass = deduceMainApplicationClass(); }
类中的run()方法
public ConfigurableApplicationContext run(String... args) {
// stopwatch 用于记录时间等
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 从spring.factories 配置文件中拿到 key为 SpringApplicationRunListener 类的 value值
// 这里就只有一个值: EventPublishingRunListener 类,在其构造方法中实例化了一个
// SimpleApplicationEventMulticaster类,并在构造方法里面把所有的spring.factories文件中listener添加给了广播器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 方法调用,点进去
listeners.starting();
// ......
}
getRunListeners()方法
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 就是添加一个 EventPublishingRunListener
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
getSpringFactoriesInstances()方法
// 这个方法就是从spring.factories配置文件中 拿到指定类型(参数 type)的类的实例
// 比如:SpringApplicationRunListener、ApplicationContextInitializer
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 比如:type就是 ApplicationContextInitializer类
// loadFactoryNames()方法就是返回 在 spring.factories配置文件中定义的 ApplicationContextInitializer 类,
// 的所有对应的value值
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
spring.factories文件中
SpringApplicationRunListeners.java
SpringApplicationRunListeners构造方法
// 这个构造方法的调用,在上面的getRunListeners()方法进行调用的 SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; // 一般传过来的listeners就一个 EventPublishingRunListener this.listeners = new ArrayList<>(listeners); }
EventPublishingRunListener.java
// 这个构造方式的调用是在上面的SpringApplication类中的getSpringFactoriesInstances()方法中实例化的 public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; // 广播器,所有的事件发生后,都是这个广播器分发给对应的listener this.initialMulticaster = new SimpleApplicationEventMulticaster(); // 把 SpringApplication类中的所有监听器添加到广播器中 for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } }
一个spring内部事件完整发布过程
一个spring容器的starting事件
首先在SpringApplication类中发布事件
然后这个调用就会进入
SpringApplicationRunListener
类中,调用其starting()方法然后这个listener.starting()调用会进入
EventPublishingRunListener
类中,调用其starting()方法!
上面的starting()方法,利用广播器,发布一个
ApplicationStartingEvent事件
上面this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args))方法调用后,就会继续调用
SimpleApplicationEventMulticaster
类的multicastEvent()方法
上面方法调用的invokeListener()
方法的内容如下:
然后doInvokeListener(listener, event)方法继续调用如下,然后调用链就完毕
上面multicastEvent()内部调用的getApplicationListeners(event, type),里面会调用如下的方法:
调用retrieveApplicationListeners()
调用supportsEvent()
最后调用supportsEvent()
这里就是我们实现的listenre接口中的两个方法,只有都返回true才会成功的订阅