SpringBoot 自动配置
SpringBoot 配置文件
配置文件
- SpringBoot 使用全局配置文件,配置文件名称固定。
- application.perperties
- application.yml
- 配置文件生效的本质,Springboot 底层的自动配置实现,可以修改底层配置的默认值。
3、配置文件加载位置。
- file:/config/ file 是指:项目文件根路径。
- file:./
- classpath:/config/
- classpath:/
说明:以上配置按照优先级顺序从高到底,所有位置的文件都会被加载到,高优先级会覆盖低优先级的配置内容。可以通过修改 spring.config.location来改变默认配置。彼此的配置会互补并集。
设置配置文件信息
- 支持
.properties
和yml
两种文件格式,全局配置文件名称固定application
。 - 支持的数据格式
key = value
,value 属性可以设置多种数据类型。- 常见基本数据类型。int、String等
- list、map 等
获取配置信息
@Value("filed")
,spring 提供的获取环境变量或配置文件中的值。@configurationProperties(prefi=xxx.xxx)
,SpringBoot 提供的注解,作用在类中,可以指定前缀为映射,获取配置文件中的信息和类属性映射。支持批量一次映射所有的属性,支持松散绑定(驼峰,下划线切分)。- 配置文件路径设置,默认从
classPath/lresource/application.properties
下获取文件,我们可以在指定文件地址。- 一、
PropertySource("Path")
,设置配置文件指定地址。 - 二、
importSource("Path")
,读取指定路径下配置文件。
- 一、
容器中添加组件
@configuration
注解:SpringBoot 推荐使用的,添加组件方式。作用在类上,指明当前类是一个配置类。- @bean 注解:作用在方法中,可以把方法返回的对象添加到容器中,添加到容器中实例 ID 名称 为方法的名称。
配置文件占位符
RandomValuePropertySource
: 配置文件可以使用随机数。例如:${random.value}、${random.int(10)}、${random.uuid}
- 属性配置文件占位符。
- 可以在配置文件中引用前面配置过的属性(优先级前配置过的都可以在这里使用)。
- ${app.name:默认值}来指定找不到属性时的默认值。
Profile 多环境配置文件
Profile 是 Spring 对不同环境提供不同配置功能的支持,可以通过激活、设置参数做到环境切换,成见使用场景 测试环境、灰度环境、线上环境。
SpringBoot 启动会默认扫描 application.properties文件或者 applcation.yml 文件,做为SpringBoot的默认配置文件。
- 多 Profile 文件形式:
格式说明:properties.{profile}.properties。例如:properties.dev.properties等 - yml 格式配置还支持多文档块配置。
方法:---
分割配置 - 激活方式:
- 命令行:--spring.profiles.active=dev
- 主配置文件: spring.profile.active=dev
- JVM 启动参数: -Dspring.profile.active=dev
外部配置加载顺序
SpringBoot 会从下列位置获取配置,优先级从高到底,相处互补配置。
- 命令行参数,--配置项=参数值 多个用空格隔开。
- 来自 java:comp/env 的 JNDI 属性
- Java 系统属性 System.getProperties()
- 操作系统环境变量
- RandomValuePropertySource 配置的 random.* 属性
- jar 外部的配置文件
- jar 包内部的配置文件
- @configuration 注解上的 @PropertySource
- 通过SpringApplication.setDefalultProperties 指定的默认属性值。
自动配置原理
自动配置原理
-
SpringBoot 启动的时候加载配置类,开启自动配置功能 @EnableAutoConfiguration。
@EnableAutoConfiguration
类上的注解@Import(AutoConfigurationImportSelector.class)
。总结:将类路径下 META-INF//spring.factories 加载到 IOC 容器,从而做到自动配置功能。
点击查看代码
```AutoConfigurationImportSelector ```注解类中
// 选择要自动配置的生效信息
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) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 加载配置条件信息
List configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
// 根据条件加载
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List 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;
}
// 加载配置名称
public static List loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
// 加载配置工厂
private static Map> loadSpringFactories(ClassLoader classLoader) {
Map> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
// 类加载器加载配置文件路径地址,会加载所有 jar META-INF 文件下,Spring.factory 文件。
// 扫描文件包装成 properties 对象,交给容器
// FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
Enumeration 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;
}