1.配置文件
SpringBoot使用下面的全局配置文件,名称固定为:
- application.properties
- application.yml
利用该文件可以修改SpringBoot在底层自动配置的默认值。
在之前用Spring时,一般是用 .xml文件作为配置文件,这里出现了以yml为后缀的文件。
2.yml简单介绍
首先yml文件主要用到YAML语言。它是类似于XML的数据描述语言,但是语法比XML简单,且以数据为中心。
可以看看下面的XML与YML对比小例子
XML:
<server>
<port>8080</port>
</server>
YAML:
server:
port:8081
可以看到上述例子中YAML语法非常简便,除了类名、属性名以及值没有多余的东西。
其他的关于YAML中的Map、List、Set等语法不多做介绍,值得一提的是一个yml文件可以分成多个文档(document),如下例:
server:
port: 8080
---
server:
port: 8081
spring:
profiles: test
通过 --- 分割,yml文件被分为两个文档,将项目打包为jar包时,我们可以通过命令行
java -jar [jar包名.jar] --spring.profiles.active=test
使得启动的端口号为8081。
3.配置文件的扫描位置
在SpringBoot中,配置文件application.properties与application.yml的放置位置不同,则扫描顺序也不同。顺序如下:
–file:./config/
–file:./
–classpath:/config/
–classpath:/
也就是说如果在项目下创建config文件夹,其中的配置文件优先级是最高的,其次是直接在项目下放置的配置文件,然后是类文件的路径下的config包,最后是类文件路径下直接放置的配置文件。高优先级配置文件会覆盖低优先级的配置文件,并且互补配置。
4.外部配置加载顺序
可以参考官方文档:
5.自动配置原理
1.首先在@SpringBootApplication中已经注释了@EnableAutoConfiguration,该注释就是开启了自动配置功能
2.@EnableAutoConfiguration,我们可以看到在下图源码中导入了 EnableAutoConfigurationImportSelector
3.EnableAutoConfigurationImportSelector 是继承了 AutoConfigurationImportSelector
@Deprecated
public class EnableAutoConfigurationImportSelector
extends AutoConfigurationImportSelector {
@Override
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
true);
}
return true;
}
}
4.AutoConfigurationImportSelector中的selectImports()方法起到了关键作用
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
其中的语句:List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes) 会进一步调用loadFactoryNames()方法,该方法会扫描所有jar包锁在的路径 META-INF/spring.factories。然后它们进一步封装到properties对象中。然后通过class属性再添加到属性中。
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
5.查看spring.factories中的url都是以xxxAutoConfiguration结尾,刚好对应每一个xxxAutoConfiguration类,它们都会被加载到容器中并自动配置。这里以HttpMessageConvertersAutoConfiguration为例
@Configuration//这里声明是一个配置类
@ConditionalOnClass(HttpMessageConverter.class)//判断当前项目有没有这个HttpMessageConverter类
@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class })
//在上面类加载后自动注入当前类
@Import({ JacksonHttpMessageConvertersConfiguration.class,
GsonHttpMessageConvertersConfiguration.class })
public class HttpMessageConvertersAutoConfiguration {
//对应映射
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";
private final List<HttpMessageConverter<?>> converters;
public HttpMessageConvertersAutoConfiguration(
ObjectProvider<List<HttpMessageConverter<?>>> convertersProvider) {
this.converters = convertersProvider.getIfAvailable();
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean //如果该注释里面有值,会判断容器有没有这个组件
public HttpMessageConverters messageConverters() {
return new HttpMessageConverters(this.converters == null
? Collections.<HttpMessageConverter<?>>emptyList() : this.converters);
}
@Configuration
@ConditionalOnClass(StringHttpMessageConverter.class)
@EnableConfigurationProperties(HttpEncodingProperties.class)
protected static class StringHttpMessageConverterConfiguration {
private final HttpEncodingProperties encodingProperties;
protected StringHttpMessageConverterConfiguration(
HttpEncodingProperties encodingProperties) {
this.encodingProperties = encodingProperties;
}
@Bean
@ConditionalOnMissingBean
public StringHttpMessageConverter stringHttpMessageConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(
this.encodingProperties.getCharset());
converter.setWriteAcceptCharset(false);
return converter;
}
}
}
6.如果配置文件中有需要配置的属性,一般在xxxxProperties类中封装。