# 2.SpringBoot-自动配置原理
# 1.自动包规则原理
springboot应用启动类:
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
2
3
4
5
6
7
8
@SpringBootApplication下的三个主要注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.demo.boot")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1)@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
2
3
4
5
6
7
8
9
10
11
@Configuration代表他是一个配置类
2)@ComponentScan
指定扫描哪些包下的Spring注解。
3)@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})//给容器中导入组件
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
2
3
4
5
6
7
8
9
10
11
12
13
@AutoConfigurationPackage标签名直译为:自动配置包,指定了默认的包规则。
AutoConfigurationPackages类下register方法
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition)registry.getBeanDefinition(BEAN);
beanDefinition.addBasePackages(packageNames);
} else {
registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
}
}
2
3
4
5
6
7
8
9
10
11
12
利用Register容器记录包路径导入包到容器中
(让自动配置类能够感知到用户主启动类的位置,从而更好地完成自动配置工作。)
# 2.初始加载自动配置类
@Import({AutoConfigurationImportSelector.class})
1.利用getAutoConfigurationEntry(annotationMetadata)给容器批量导入一些组件
2.调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3.利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4.从META-INF/spring.factories位置来加载一个文件。 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件 spring-boot-autoconfigure-2.7.2.RELEASE.jar包里面也有META-INF/spring.factories
# 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
# spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
...
2
3
4
5
6
7
虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration按照条件装配规则(@Conditional),最终会按需配置。
# 3.自动配置流程
SpringBoot会先加载所有的自动配置类
每个配置类都按照条件进行生效,默认都会绑定配置文件指定的值。(xxxProperties里面读取,xxxProperties和配置文件进行了绑定)
生效的配置类就会给容器中装配很多组件,只要有这些组件,相当于功能就有了
定制化配置
- 用户自己去定义Bean替换底层组件(SpringBoot底层配置好了所有的组件,如果你自己配置了优先以用户定义的优先)
@Bean
public CharacterEncodingFilter characterEncodingFilter(){
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}
2
3
4
5
6
7
- 从application.properties配置文件里面去修改默认属性值(xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 (绑定)----> application.properties)
server:
port: 8888
servlet:
encoding:
charset: UTF-8
2
3
4
5
注意:规范
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {//有参数的情况
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;//给容器中加入了文件上传解析器;
}
2
3
4
5
6
7
8
9
也就是说为了规范,他会将你注册命名的组件以规范的方式重新给你命名。
# 4.自动配置-总结
1)找到@SpringBootApplication 注解中的@EnableAutoConfiguration
2)@EnableAutoConfiguration注解中的@AutoConfigurationPackages会利用Register容器记录启动类所在的包路径,导入包路径到spring容器中
3)加载自动配置类:AutoConfigurationImportSelector读取 Spring Boot中spring-boot-autoconfigure包的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件加载到容器中
4)@Conditional 系列注解判断自动配置类是否生效,若生效,默认绑定配置文件指定的值
5)注册 Bean 到容器
| 组件 / 文件 | 作用 |
|---|---|
| @EnableAutoConfiguration | 开启自动配置的核心注解 |
| @AutoConfigurationPackages | 导入包路径到spring容器中 |
| AutoConfigurationImportSelector | 加载自动配置类清单的核心类 |
| META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 自动配置类的清单文件(Spring Boot 2.7+ 替代旧的 spring.factories) |
| @Conditional 系列注解 | 条件筛选,控制自动配置类是否生效 |
| spring-boot-autoconfigure 依赖 | 包含所有内置的自动配置类(如 WebMvcAutoConfiguration、DataSourceAutoConfiguration) |