SpringBoot自动装配原理
- pom.xml
- spring-boot-dependencies核心依赖在父工程中
- 在引入springboot依赖时,不需要写版本,因为父工程中有版本仓库。
- 启动器 spring-boot-starter-xxx
- 例如,spring-boot-starter-web,就会帮我们导入web环境所有的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 主程序SpringbootApplication .java
package com.arlin.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
表面理解:
- 注解@SpringBootApplication:标注这个类是一个springboot的应用
- SpringApplication.run(SpringbootApplication.class, args);//将springboot应用启动
深层次(源码分析):
自动装配原理分析图
-
注解@SpringBootApplication是一个复合 Annotation
-
核心的两个注解:@SpringBootConfiguration和@EnableAutoConfiguration
-
@SpringBootConfiguration
:springboot的配置
- @SpringBootConfiguration注解下还包含:@Configuration:表示一个普通的 JavaConfig 形式的 IoC 容器配置类
- @Configuration注解下包含:@Component:表示该配置类也是容器中的一个组件
-
@EnableAutoConfiguration
:开启自动配置功能
-
借助
@Import
的帮助,将所有符合自动配置条件的 bean 定义加载到 IoC 容器 -
AutoConfigurationImportSelector
:导入哪些组件的选择器。将所有需要导入的组件以全类名的方式返回,这些组件会被添加其中
① 在AutoConfigurationImportSelector类中,实现了 DeferredImportSelector 接口,而 DeferredImportSelector 是继承 ImportSelector 类的。在 ImportSelector 中有个非常重要的方法:selectImports
:批量将类注入到IOC容器
// 1. 批量将类注入到IOC容器
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
② selectImports方法调用getAutoConfigurationEntry方法
// 2. selectImports方法调用getAutoConfigurationEntry方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
③ getAutoConfigurationEntry方法调用getCandidateConfigurations方法:获取候选配置
// 3. 获取候选配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
④ 调用SpringFactoriesLoader类中的loadFactoryNames方法,之后进入loadSpringFactories方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
可以看到在loadSpringFactories方法中调用如下z路径:META-INF/spring.factories
,从中获取EnableAutoConfiguration指定的值。
META-INF/spring.factories配置文件中的所有自动配置类:
SpringBoot不需要写配置文件的原因是:SpringBoot所有配置都是在启动的时候进行扫描并加载,SpringBoot的所有自动配置类都在Spring.factories里面,但是不一定会生效,生效前要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器就能帮我们进行自动配置类
每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。
- @ComponentScan 的功能其实就是自动扫描并加载符合条件的组件或 bean 定义,最终将这些 bean 定义加载到容器中。
结论
1. SpringBoot的自动装配原理:
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,通过@Bean导入到Spring容器中,以Properties结尾命名的类是和配置文件进行绑定的。它能通过这些以Properties结尾命名的类中取得在全局配置文件中配置的属性,我们可以通过修改配置文件对应的属性来修改自动配置的默认值,来完成自定义配置。
2. SpringbootApplication类的作用:
- 1.推断应用的类型是普通的项目还是Web项目
- 2.查找并加载所有可用初始化器,设置到initializers属性中
- 3.找出所有的应用程序监听器,设置到listeners属性中
- 4.推断并设置main方法的定义类,找到运行的主类