springBoot监听器的主要分为两类:
运行时监听器和上下文监听器都是定义在spring.factories文件中。
1)运行时监听器
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
2)上下文监听器
org.springframework.context.ApplicationListener=\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
springBoot运行时监听器作用是用来触发springBoot上下文监听器,再根据各监听器监听的事件进行区分。
这是一种观察者模式,即订阅-发布模式
Multicaster中注册着多个Listener,Multicaster会发布事件,其过程就会遍历其中注册的Listener,每个Listener都针对这个事件做出响应,这就是Listener订阅,Caster发布
我们来看看运行时监听器EventPublishingRunListener的方法
它主要监听这几个事件,在这几个时间点,spring会调用其方法发布事件,然后触发上下文监听器去做出响应
跟一下springboot启动的源码,开始就是监听器的注册
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//获取监听器,并且注册到发布器上
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这里跟一下getSpringFactoriesInstances 方法,其中包含如何获取初始的监听器的,这个方法很重要在springboot中很常见,因为spring boot的自动配置好多都是靠读取这些已有的文件来获取类名,然后反射实例化来实现自动配置的
private Collection extends T> getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 获取监听器的类的全限定名
Set names = new LinkedHashSet(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化监听器
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
public static List loadFactoryNames(Class> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
//FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
//从文件读取listener的类名
Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List result = new ArrayList();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
我们从上面可以看出,监听器的类名存储在META-INF/spring.factories文件中,spring通过读取该文件来获得类名,并且实例化得到监听器,最后把它们注册得到发布器上
这样我们就可以得到一个完整的注册了listener的发布器listeners
我们从一个listeners.starting()(发布器默认的发布事件之一,也是springboot启动时的环节之一)的源码来看发布器是如何发布事件,监听器是如果处理对应的事件的
到这里就可以看到,发布器在发布事件时,新建一个对应的事件,然后遍历注册在其中的监听器响应事件
public void starting() {
//这里可以看到new了一个startedEvent,用于表名发布的是start事件
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//循环遍历发布器中的listener
for (final ApplicationListener> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
public void run() {
invokeListener(listener, event);
}
});
}
else {
//调用监听器来响应事件
invokeListener(listener, event);
}
}
}
跟一些监听器响应事件的源码,从下面可以看到,监听器通过判断事件的类别,来调用相应的处理函数,这就是个多分枝选择结构
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
以上就是SpringBoot中监听器的初始化和执行逻辑,这里我没有详细介绍每个Listener的功能,springboot中会有一些关键的功能会在一些重要的Listener中执行,到时我会详细介绍这些关键的Listener
自定义Listener有多种方式
详细见:https://blog.csdn.net/ignorewho/article/details/80702827
自定义的Listener分为两类:
1、存在于context的Listener集合中,参与spring启动的各个环节
2、存在于beanfactory中,与其他实例化的bean同时被加载,不会参与spring启动阶段的事件
(1)参与spring启动的listener
在启动类启动前先将Listener加入到listeners集合中
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
System.setProperty("version",args[0]);
SpringApplication springApplication = new SpringApplication(MainApplication.class);
springApplication.addListeners(new MyListener1());
springApplication.run();
}
}
自定义的Listener代码
public class MyListener1 implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
System.out.println("starting");
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
System.out.println("EnvironmentPrepared");
}
else if (event instanceof ApplicationPreparedEvent) {
System.out.println("Prepared");
}
else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
.getApplicationContext().getParent() == null) {
System.out.println("ContextClosed");
}
else if (event instanceof ApplicationFailedEvent) {
System.out.println("Failed");
} else if(event instanceof MyEvent){
System.out.println("MyEvent");
}
}
}
自定义的event代码
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
(2)不参与spring的启动,只用了监听自定义的事件
这只需要在MyListener前面加上@Component标签,不需要在启动程序中手动addListener了
@Component
public class MyListener1 implements ApplicationListener {...}
这两种情况之所以不同,是因为listener添加的时机和位置不同,一个在spring启动前就已经添加了,一个在Spring实例化bean之后才被放到beanfactory中