SpringBoot源码-前置知识:从源码层面讲解SPI、spring.factories的加载、事件监听机制

前置知识:

一、什么是SPI以及spring.factories文件的加载解析流程

什么是SPI?

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的 META-INF/services 文件夹查找文件,自动加载文件里所定义的类。这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。

什么是SpringFactoriesLoader?

它其实和java中的SPI机制的原理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据key进行加载。
首先,SpringFactoriesLoader的作用是从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。

spring.factories介绍
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));这个方法是解析该文件的入口,在springboot中,需要获取spring.factories文件中的实例对象了调这个方法,先读取names再createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);通过反射生成。
在springBoot项目启动的过程中需要用到两个名称为spring.factories的文件,该文件存在于
org\springframework\boot\spring-boot\2.2.2.RELEASE\spring-boot-2.2.2.RELEASE.jar!\META-INF\spring.factories
org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar!\META-INF\spring.factories
这个文件内部存的是一个K-V键值对,内容如下:
spring-boot-2.2.2.RELEASE.jar:

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

spring-boot-autoconfigure-2.2.2.RELEASE.jar:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

上面两个文件的加载解析到内存的堆栈调用路径如下:
在SpringApplication 的构造方法中

loadSpringFactories:133, SpringFactoriesLoader (org.springframework.core.io.support)
loadFactoryNames:122, SpringFactoriesLoader (org.springframework.core.io.support)
getSpringFactoriesInstances:490, SpringApplication (org.springframework.boot)
getSpringFactoriesInstances:473, SpringApplication (org.springframework.boot)
<init>:278, SpringApplication (org.springframework.boot)
<init>:254, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)

在这里插入图片描述
ApplicationContextInitializer.class和ApplicationListener.class在上面两个spring.factories文件都能找到对应的类的全限定名:

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener


然后将这些类实例化进行构造函数成员变量赋值。
loadFactoryNames:从“META-INFspring”中加载给定类型的工厂实现的完全限定类名。工厂”,使用给定的类装入器
在这里插入图片描述
从上可以看到org.springframework.context.ApplicationContextInitializer对应的有7个,直接一次将META-INF/spring.factories所有值加载,后续直接根据key获取即可。该方法返回names然后进行实例化,后续所有此操作都一样。
在这里插入图片描述

二、SpringBoot中监听器的加载和执行流程、发布事件的执行源码分析

1、上面在SpringApplication的构造方法中有初始化监听器,方法如下:

		// 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

通过上文分析可知,读取spring.factories文件获取到ApplicationListener对应的类路径为:

org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

共计11个,这些是内置的监听器,后续发布事件由这些监听器执行onApplicationEvent方法,前提条件是方法的event和发布的事件一致才行。

2、内置的事件触发器

run:331, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)

重点看SpringApplicationRunListeners listeners = getRunListeners(args);方法:
在这里插入图片描述
getRunListeners实现:

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				// getSpringFactoriesInstances 读取spring.factories 文件中key 为 SpringApplicationRunListener 类型的
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

spring.factories文件显示的类路径:

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

SpringApplicationRunListener的实现类是EventPublishingRunListener从文件可以看出
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)会完成实例化操作
在这里插入图片描述
这里的参数对应EventPublishingRunListener构造函数的参数:
在这里插入图片描述
在SpringApplication构造函数中实例化了11个监听器,这里又把SpringApplication对象的监听器放到EventPublishingRunListener的成员变量initialMulticaster中,后续执行监听事件就是用它。至此,监听器和EventPublishingRunListener绑定在一起,EventPublishingRunListener可以理解为广播器。下面开始讲解监听事件的执行流程:
在这里插入图片描述
listeners.starting();开始触发事件
在这里插入图片描述
List listeners只有一个实例,
在这里插入图片描述
可以看到这里发布的事件是ApplicationStartingEvent,继承自SpringApplicationEvent以及发布事件的类图
在这里插入图片描述
最终执行的是multicastEvent方法,getApplicationListeners(event, type)会返回所有监听了ApplicationStartingEvent事件的监听器,然后用来遍历执行监听器的onApplicationEvent方法。每个监听器的onApplicationEvent实现的细节不同。
在这里插入图片描述
getApplicationListeners实现细节如下:

retrieveApplicationListeners:281, AbstractApplicationEventMulticaster (org.springframework.context.event)
getApplicationListeners:197, AbstractApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:134, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
starting:75, EventPublishingRunListener (org.springframework.boot.context.event)
starting:49, SpringApplicationRunListeners (org.springframework.boot)
run:333, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)

retrieveApplicationListeners返回监听该事件的监听器:
在这里插入图片描述
LoggingApplicationListener 这个监听器的执行堆栈:

onApplicationStartingEvent:239, LoggingApplicationListener (org.springframework.boot.context.logging)
onApplicationEvent:220, LoggingApplicationListener (org.springframework.boot.context.logging)
doInvokeListener:172, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
starting:75, EventPublishingRunListener (org.springframework.boot.context.event)
starting:49, SpringApplicationRunListeners (org.springframework.boot)
run:333, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)
	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();
		}
	}

然后执行onApplicationStartingEvent((ApplicationStartingEvent) event);:
LoggingApplicationListener 执行之后,继续遍历其他的监听器的onApplicationEvent方法,完成

// 触发启动事件 发布 starting 事件 --》 那么监听starting事件的监听器就会触发
listeners.starting();

.listeners.starting();就讲完了,后续其他的事件也都是这个流程,逐步分析即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值