一、SpringBoot的基础使用
SpringBoot框架非常庞大,功能也非常多,基本上成了现在J2EE开发方向的事实标准。以SpringBoot扩展出来的生态圈基本上涵盖了所有的技术方向。对于SpringBoot,可以轻易的查出上百种使用方式,但是SpringBoot到底是什么样的?哪些功能是Spring的,哪些是SpringBoot的?要怎么全面深度的去学习以及把握SpringBoot框架呢?很多时候其实都是很模糊的。
这一系列文字只是为了记载学习SpringBoot框架底层的一些学习笔记。有些是自己写的,有些是网上收集的。会更多关注底层,而关于SpringBoot的使用,会有简单介绍,但不是重点。你只需要搭建一个简单的SpringBoot项目,就能把整个过程跟踪下来。
二、SpringBoot底层整体理解
SpringBoot框架的整体功能其实都浓缩在spring.factories文件当中。
我们创建SpringBoot工程后,会引入一个mave依赖:org.springframework.boot:spring-boot-starter:2.4.5。这个依赖就是SpringBoot的基础依赖。 在对应的spring-boot-2.4.5.jar这个包中,就会包含有spring.factories配置文件。SpringBoot框架就是围绕这个配置文件来展开他的所有功能实现的。
这里采用目前最新的稳定版本2.4.5来测试
打开文件内容,这其实就是一个key-value形式的配置文件,大致是这样一个结构
# Logging Systems
org.springframework.boot.logging.LoggingSystemFactory=...
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=...
# ConfigData Location Resolvers
org.springframework.boot.context.config.ConfigDataLocationResolver=...
# ConfigData Loaders
org.springframework.boot.context.config.ConfigDataLoader=...
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=...
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=...
# Application Listeners
org.springframework.context.ApplicationListener=...
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=...
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=...
# Failure Analysis Reporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=...
那现在我们就要来理解下这个配置文件:
首先:这个配置文件中每一个配置就对应了SpringBoot中提供的一种功能机制。
这个配置文件,从形式上看,就能很容易的理解为一种类似于JAVA的SPI扩展机制的配置文件。每个key对应一个功能接口,后面的value对应这个接口的多个实现。但是这里的功能实现,并不是全指java中的接口实现类,而是与这个功能相关的核心实现类,这个在后面的细节讲解中会体会到。
很多功能从接口名字上也能有个大致的理解。例如org.springframework.context.ApplicationListener 对应SpringBoot的事件监听功能。org.springframework.context.ApplicationContextInitializer对应SpringBoot的框架启动初始化功能。针对每个功能,他们的加载以及工作的流程机制是不一样的,但是正是这些机制构成了SpringBoot框架的整体。我们想要整体把握SpringBoot框架,就需要从这些功能入手。
然后:这个配置文件是可以扩展的。
在SpringBoot的基础maven依赖org.springframework.boot:spring-boot-starter:2.4.5下,还包含了另外一个基础的依赖org.springframework.boot:spring-boot-autoconfigure:2.4.5。这个依赖对应的jar包下同样有一个spring.factories文件。大概结构是这样:
# Initializers
org.springframework.context.ApplicationContextInitializer=...
# Application Listeners
org.springframework.context.ApplicationListener=...
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=...
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=...
# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=...
# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=...
他在spring-boot-starter的spring.factories文件基础上,又增加了一些配置。正是这些配置一起实现了SpringBoot的自动装配。也就是说,SpringBoot会扫描ClassPath下的所有META/spring.factories文件,整合到一起形成项目的基础功能配置,然后以这些配置信息为基础,实现出不同的功能。
当然,SpringBoot在上层扩展实现的过程当中,也还出现了非常多扩展机制,以至于基于spring.factories文件的扩展方式在实际开发过程中其实用得非常少了。但是,其实这才是SpringBoot框架的真正核心。
另外,从这里看出,SpringBoot框架内部其实有很多组件就是通过这个机制扩展出来的。那既然这种扩展机制,在框架内部可以用,那我们在使用SpringBoot框架时,同样也是可以用的。
三、SpringBoot的SPI加载机制
后面的部分也就会按照这个配置文件功能逐一进行梳理。在开始之前,肯定还是要了解下SpringBoot是如何来加载这些配置的。上面提到的整个spring.factories文件的加载过程,都在 org.springframework.core.io.support.SpringFactoriesLoader 这个类当中,所属jar包:spring-core-5.3.6.jar。查看下他的loadSpringFactories方法。
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
在这个类下,还可以按照接口和classloader来查找具体的实现类。但是最为核心的就是这个方法。是整个SpringBoot读取配置信息的基础。
然后在一个只包含了简单的spirngBoot的web依赖(Maven依赖 org.springframework.boot:spring-boot-starter-web)的项目中启动,并在这个方法的return result一行加个断点,可以看到SpringBoot默认加载到的spring.factories配置有16个。
2.2.3版本还只有13个,到2.4.5版本增加到了16个。
这16个配置就对应了SpringBoot的16个核心功能点。在这每个功能点后不断的叠加实现类,就最终完成了Spring到SpringBoot的蜕变。而这16个功能点,也就是后面要梳理的重点。后面争取将这每一个功能点都梳理一遍,相信通过这样的梳理,就能够将SpringBoot使用过程中各种莫名其妙的“秘籍”有个整体的把握。
网上找了很多文章,很多功能点都有,但是非常零散。对于SpringBoot的说明也大都是集中在任何使用,很少有说明这些功能点的核心实现机制的。这里权当收集总结,加上自己的一些理解把。