SpringBoot源码分析一(自动装配原理)
文章目录
官网:https://spring.io/projects/spring-boot
目前最新版本为 2.6.2
简介:来自官网第一句话。
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.
Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,您可以“直接运行”这些应用程序。
大多数 Spring Boot 应用程序需要最少的 Spring 配置。
什么是Spring Boot
- 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动配置)的理念让你的项目快速运行起来。
- 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一样,Spring Boot 整合了所有框架
特点
- 创建独立的 Spring 应用程序
- 直接嵌入Tomcat、Jetty或Undertow(无需部署WAR文件)
- 提供自以为是的“入门”依赖项以简化您的构建配置
- 尽可能自动配置 Spring 和 第三方库
- 提供生产就绪功能,例如指标、运行状况检查和外部化配置
- 完全不需要代码生成,也不需要 XML 配置
maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springboot-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
</project>
入口
@SpringBootApplication
@RestController
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@GetMapping("")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
@SpringBootApplication
这个注解标注于某个类上,说明这个类是Spring Boot的主配置类,通过运行这个类的 main 方法来启动 Spring Boot。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
@SpringBootConfiguration
- Spring Boot的配置类
- 标注在某个类上,表示这是一个Spring Boot的配置类
注解定义如下:
@Configuration
public @interface SpringBootConfiguration {}
其实就是一个
Configuration配置类
,意思是 MyApplication 最终会被注册到Spring容器中
@EnableAutoConfiguration
- 开启自动配置功能
- 以前使用Spring需要配置的信息,Spring Boot帮助自动配置;
-
@EnableAutoConfiguration
通知SpringBoot开启自动配置功能,这样自动配置才能生效。
注解定义如下:
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage
- 自动配置包注解
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
@Import(AutoConfigurationPackages.Registrar.class)
:默认将主配置类(
@SpringBootApplication
)所在的包及其子包里面的所有组件扫描到Spring容器中。如下
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
@Import(AutoConfigurationImportSelector.class)
EnableAutoConfigurationImportSelector: 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
...
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
...
}
getCandidateConfigurations()
方法会给容器中注入众多的自动配置类(xxxAutoConfiguration),就是导入这个场景所需要的所有组件,并配置好这些组件。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
loadFactoryNames()
从类路径的META-INF/spring.factories中加载所有默认的自动配置类
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
......
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
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);
......
// 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;
}
SpringBoot启动的时候从类路径下的
META-INF/spring.factories
中获取EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,自动配置类就会生效,最后完成自动配置工作。EnableAutoConfiguration默认在spring-boot-autoconfigure这个包中。
在这里插入图片描述
最终有96个自动配置类被加载并注册进Spring容器中。
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-xxx.jar中。在这些自动配置类中会通过@ConditionalOnClass等条件注解判断是否导入了某些依赖包,从而通过@Bean注册相应的对象进行自动配置。后面我们会有单独文章讲自动配置的内容
@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
核心方法:
selectImports() -> getAutoConfigurationEntry() -> getCandidateConfigurations() -> SpringFactoriesLoader.loadFactoryNames() -> loadSpringFactories()
总结:
路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
## 核心方法:
selectImports() -> getAutoConfigurationEntry() -> getCandidateConfigurations() -> SpringFactoriesLoader.loadFactoryNames() -> loadSpringFactories()
## 总结:
> SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories文件中的所有自动配置类,并对其加载,这些自动配置类都是以AutoConfiguration结尾来命名的。它实际上就是一个JavaConfig形式的IOC容器配置类,通过以Properties结尾命名的类中取得在全局配置文件中配置的属性,如server.port。