SpringBoot 中的配置文件以及自动配置原理

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类中封装。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值