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.javapublic class App { public static void main(String[] args) { // SpringApplication.run(App.class); // 这里的构造方法里面得到了所有的listener SpringApplication application = new SpringApplication(App.class); application.run(args); } } -
SpringApplication.javaSpringApplication的构造方法,里面得到所有的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.javaSpringApplicationRunListeners构造方法// 这个构造方法的调用,在上面的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才会成功的订阅
-