SpringBoot 配置文件与自动装配原理

1,419 阅读4分钟

1.关于 SpringBootSpringBoot 的配置文件

1.0 配置文件的类型

SpringBootSpringBoot 支持以下两类配置文件。

  1. 后缀为 .properties.properties 的文件

  2. 后缀为 .yml.yml 的文件

1.1 配置文件的位置

在创建一个 SpringBootSpringBoot 工程时,默认在 resourcesresources 目录下有一个 application.propertiesapplication.properties 文件,这个文件就是 SpringBootSpringBoot 自带的配置文件。但配置文件的位置并不是固定的。按照官方文档的介绍,配置文件可以放在以下四个位置,且优先级依次降低。

  • 项目的根目录下的 configconfig 文件夹中(这个文件夹默认不存在,需要的话要自己创建)
  • 项目的根目录下
  • resourcesresources 目录下的 configconfig 文件夹中(这个文件夹默认不存在,需要的话要自己创建)
  • resourcesresources 目录下(resources下就是classpathresources下就是classpath下

SpringBootSpringBoot 会依次加载这四个位置的配置文件,优先级高的配置会覆盖优先级低的配置,并形成互补配置。

当然,配置文件的位置也可以自己指定,但若不做相应的调整 ,SpringBootSpringBoot 并不会去加载自定义的配置。我们可以在

<img src="D:\自媒体运营\微信公众号图片\SpringBoot配置文件位置.png" alt="SpringBoot配置文件位置" style="zoom:60%;" />

设置spring.config.location=classpath:/路径/,这样项目启动时就加载的是自定义路径下的配置文件了。

若是jar包,我们可以通过下方命令修改路径。

java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=路径

1.2 配置文件的名字

SpringBootSpringBoot 默认加载的配置文件的名字都为 application.xxx,但也可以是 application-{profile}.xxx 以应对多环境下不同的配置。但如有特殊需要,一定要修改application这个名字,并且保证 SpringBootSpringBoot 默认加载自定义的配置文件,我们可以参照修改配置文件路径的方式,只不过这次是 spring.config.name=名字

对于不同环境下的配置,若要激活对应的配置文件,需要在默认的配置文件 application.xxx 中加 spring.profiles.active=xxx 来激活。

1.3 配置文件的内容

  1. 字面量,如基本数据类型
  2. 对象
  3. 数组
  4. List,Set,Map等
  5. 占位符,如随机数 \{random.*}$

1.4 利用配置文件注入属性

  1. 基于 @Value@Value 注解,给已经在容器中JavaBeanJavaBean 注入属性
@Component
public class Dog{
    @Value("${dog.name}")
    private String name;
    //省略get/set方法
}

配置文件application.properties中
dog.name=BigDog
  1. 使用 @ConfigurationProperties@ConfigurationProperties 注解,给已经在容器中JavaBeanJavaBean 注入属性
@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {
    private String name;
    //省略get/set方法
}

配置文件application.properties中
dog.name=BigDog

若我们需要给一个 BeanBean 注入一个自定义的配置文件的属性,可以在 BeanBean 上加 @PropertySource("classpath:配置文件")@PropertySource("classpath:配置文件") 注解,表明这个 BeanBean 会加载我们指定的配置文件。

@PropertySource(value = {"classpath:dog.properties"})
@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {
    private String name;
    //省略get/set方法
}

配置文件application.properties中
dog.name=BigDog

比较两种注入属性的方法

@ConfigurationProperties@Value
功能批量注入配置文件中的属性一个个指定
松散绑定(松散语法)支持不支持
SpEL不支持支持
JSR303数据校验支持不支持
复杂类型封装支持不支持

2.SpringBootSpringBoot 自动装配原理

SpringBootSpringBoot 自动装配的关键都在 @EnableAutoConfiguration@EnableAutoConfiguration 注解中。

进入 @EnableAutoConfiguration@EnableAutoConfiguration 中,可以看见它上面的注解

@EnableAutoConfiguration注解

重点关注 @Import@Import 注解。

这个注解是 SpringSpring 中的注解,可以用来给容器中注入一个 BeanBean ,而这里就是要给容器中注入一个AutoConfigurationImportSelectorAutoConfigurationImportSelector 类,这个类实现了 DeferredImportSelectorDeferredImportSelector 接口,这个接口继承了 ImportSelectorImportSelector 接口。

所以这个类必须重写String[] selectImports(AnnotationMetadata importingClassMetadata);方法,而这个方法的功能,返回一个包含要注入到容器中的Bean的名称的数组,元数据由配置类提供(@Configuration@Configuration)。

/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 * @return the class names, or an empty array if none
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

这个方法底层扫描了所有META-INF/spring.factories配置文件中的内容,所有需要创建的 BeanBean 都在这里面,读取每个 starterstarter 中的spring.factoriesspring.factories 文件,封装成 propertiesproperties 对象,通过迭代器遍历取值,添加到容器中。

底层装配

随便打开一个META-INF/spring.factories内容,都是一个个自动配置类 xxxAutoConfigurationxxxAutoConfiguration

spring.factories

AopAutoConfigurationAopAutoConfiguration类为例

aop自动配置类

可以看见 @Configuration@Configuration 注解,说明就是一个配置类,而这些配置类会提供元数据AnnotationMetadata importingClassMetadata,也能看见 @ConditionalOnXXX@ConditionalOnXXX注解,说明要满足某些条件,这个BeanBean才能被加入容器中。

总结:借由@EnableAutoConfiguration@EnableAutoConfiguration 注解,找到METAINF/spring.factoriesMETA-INF/spring.factories文件,读取文件中的内容,而该文件里面都是一个个要被注入容器中的BeanBean,满足条件后就被加入容器中,完成装配。

更多Java内容欢迎关注我的公众号ACJavaBear,文章第一时间会发在上面。一起学Java吧