一:概述

在Spring boot 中根据业务需求,我们往往会在不同地方配置我们所需的key-value 配置项,配置文件存在不同的地方的场景如下:

(1) 默认存在 application.properties 或 application.yaml ,而这些文件可以放在项目的不同地方,如:项目根目录下、项目根目录/config下、src/main/resources下、src/main/resources/config下、引用的工程中,甚至这两个文件同时存在;

(2) 针对 (1) 中的 application.properties 或 application.yaml , 又存在不同环境的配置;

(3) 上述的配置文件中可以配置 Spring boot 的 key 配置,如:server.port、spring.datasource.* 配置等,同时也可配置我们自定义的 key ;

(4) 为了不让 application.properties 变得臃肿,我们会将项目所需 的 key 配置放置在自定义的配置文件中,而该配置文件可以向 (1) 中一样放在任何位置上;

二:功能介绍

1、 自定义配置

(1) 自定义配置 存储在 application.xml 或 application.yaml

使用 @ ConfigurationProperties 注解 或直接使用 @Value 直接进行注解注入属性值

使用 @ ConfigurationProperties 根据 prefix 注解进来的属性上,可以不加注解,但是需要需要有对应的 setter方法,否则值设置不进去;

使用 @Value 方法可以没有 setter方法,它是通过别的方式将值设置进去的;

示例如下:

package com.example.demo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; /**
 * 自定义配置属性注入(配置项存储在 application.properties 中)
 *
 * @author sandy
 *
 */
@Component
@ConfigurationProperties(prefix = "hello")
public class CoustomPropertiesInjectV1 {
    private String username;
    @Value("${hello.test.username}")
    private String testUsername;
    
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getTestUsername() {
        return testUsername;
    }
    public void setTestUsername(String testUsername) {
        this.testUsername = testUsername;
    }
}
@GetMapping("/configurationProperties")
    public CoustomPropertiesInjectV1 findPropertiesInjectV1(){
        return propertiesInjectV1;
    }

说明:

  • 在项目的 src/main/resources 下存在 applicaton.properties文件,在该文件中存在 hello 为前缀的配置项,主要为:
# 自定义配置项
hello.username=sandy_classpath_applicaiton_properties
hello.test.username=test_classpath_applicaiton_properties
  • 针对 hello.username 在  @ConfigurationProperties(批量注入直接,自动注入同个前缀不同配置项) 已经配置了 前缀,表示把前缀为 “hello” 的配置均注入到当前类属性中,但是 仅能将 前缀.XXX 注入到当前类中 同名 XXX 属性中;
  • 在使用 @ConfigurationProperties 时,需要增加 Maven 依赖项:
 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
  • 根据上面了解 hello.test.username 是无法通过 前缀注入进来的,因为类中的属性名不能含有 ".",因此 test.username 不能作为属性名,此时可以使用 @Value 进行注入;

根据上面介绍,自定义配置项注入可以使用两个注解:@ConfigurationProperties 或 @Value;

(2) 自定义配置项存在在自定义的配置文件(文件名不为 applicaiton)

a)  在类上加上注解:@PropertySource,指明加载自定义的配置文件 (仅适用于 properties文件)

package com.example.demo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component; /**
* 自定义配置属性注入(配置项存储在cutom.properties 中)
* <li>虽然配置了 @PropertySource,并指明了加载其他文件的配置项,但是实际上仍会去application.properties中加载配置<br>
* 当该类的配置项key与applicaiton.properties中一致时,加载了 applicaiton.propeties中的同名key属性值;
* </li>
* <li>自定义配置文件在类上下文时,value中可加上 classpath 指明文件在类路径下,或者不加这个,也默认是在类路劲下</li>
* <li>加载文件系统文件,自定义配置文件不在类路径下,使用file,默认从项目跟路径下加载</li>
* <li>@PropertySource 的value 属性可以指定多个地方的配置文件,若不同文件中存在同名key,则后者覆盖前者</li>
* @author sandy
*
*/
@PropertySource(value={"classpath:custom.properties","file:config/custom-config-dir.properties"})
@Component
@ConfigurationProperties(prefix = "hello")
public class CoustomPropertiesInjectV2 {
private String usernameV2;
@Value("${hello.test.usernameV2}")
private String testUsernameV2; /***与application.properties 文件存在同名key配置项***/
private String username;
@Value("${hello.test.username}")
private String testUsername; public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getTestUsername() {
return testUsername;
}
public void setTestUsername(String testUsername) {
this.testUsername = testUsername;
}
public String getUsernameV2() {
return usernameV2;
}
public void setUsernameV2(String usernameV2) {
this.usernameV2 = usernameV2;
}
public String getTestUsernameV2() {
return testUsernameV2;
}
public void setTestUsernameV2(String testUsernameV2) {
this.testUsernameV2 = testUsernameV2;
}
}
@GetMapping("/configurationProperties/V2")
public CoustomPropertiesInjectV2 findPropertiesInjectV2(){
return propertiesInjectV2;
}

配置文件 在 项目目录/config/custom-config-dir.properties 、类路径下/custom.properties

项目目录/config/custom-config-dir.properties文件内容如下:

hello.usernameV2=sandy_root_config_dir_custom_propeties
hello.test.usernameV2=test_root_config_dir_custom_propeties hello.username=sandy_root_config_dir_custom_propeties
hello.test.username=test_root_config_dir_custom_propeties

类路径下/custom.properties 如下:

hello.usernameV2=sandy_classpath_custom_propeties
hello.test.usernameV2=test_classpath_custom_propeties hello.username=sandy_classpath_custom_propeties
hello.test.username=test_classpath_custom_propeties

访问 该 restful 接口,返回内容如下:

{
    "usernameV2": "sandy_root_config_dir_custom_propeties",
    "testUsernameV2": "test_root_config_dir_custom_propeties",
    "username": "sandy_classpath_applicaiton_properties",
    "testUsername": "test_classpath_applicaiton_properties"
}

综上可以得到以下结论:

  • 通过 propertiesSource 标签指定加载的配置文件,若没有说要加载 application.properties文件,默认会加载 application.properties文件;
  • 自定义配置文件中存在与 application.properties 中 同名 key,则以application.properties中的同名 key 值为准;
  • propertiesSource  value属性可以指定多个外部文件,不同文件存在同名 key,后加载的覆盖前者同名 key 值;

b) 自定义文件为 yml文件,装载方式使用 @bean

在前面基础上增加以下类

package com.example.demo.config.dto;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Component
public class CoustomYamlInjectV1 {
private String usernameV2;
@Value("${yml.test.usernameV2}") //最终值为 工程目录下/config/custom-config-dir.yml 文件中的值
private String testUsernameV2; /***与application.properties 文件存在同名key配置项***/
private String username;
@Value("${hello.test.username}")
private String testUsername; //最终值为 application.properties中的值
@Value("${hello.test.usernameV2}") //最终值为 config/config/custom-config-dir.properties 文件中的值
private String helloTestUsernameV2; public String getHelloTestUsernameV2() {
return helloTestUsernameV2;
}
public void setHelloTestUsernameV2(String helloTestUsernameV2) {
this.helloTestUsernameV2 = helloTestUsernameV2;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getTestUsername() {
return testUsername;
}
public void setTestUsername(String testUsername) {
this.testUsername = testUsername;
}
public String getUsernameV2() {
return usernameV2;
}
public void setUsernameV2(String usernameV2) {
this.usernameV2 = usernameV2;
}
public String getTestUsernameV2() {
return testUsernameV2;
}
public void setTestUsernameV2(String testUsernameV2) {
this.testUsernameV2 = testUsernameV2;
}
}
package com.example.demo.config;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource; /**
* 测试加载自定义 yaml文件
* @author sandy
*
*/
@Configuration
public class CoustomYamlConfigV1 {
@Bean
public static PropertySourcesPlaceholderConfigurer loadProperties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
//yaml.setResources(new FileSystemResource("classpath:config/user.yml"));//File路径引入
yaml.setResources(new ClassPathResource("coustom.yml"),new FileSystemResource("config/custom-config-dir.yml"));//class路径引入
configurer.setProperties(yaml.getObject());
return configurer;
}
}
@GetMapping("/yml")
public CoustomYamlInjectV1 findYamlInject(){
return coustomYamlInjectV1;
}

yml配置文件如下:

src/main/resources/custom.yml

yml:
usernameV2: sandy_classpath_custom_yml
test:
usernameV2: test_classpath_custom_yml hello:
usernameV2: sandy_classpath_custom_yml
username: sandy_classpath_custom_yml
test:
usernameV2: hello_test_classpath_custom_yml
username: test_classpath_custom_yml

工程目录下/config/custom-config-dir.yml

yml:
usernameV2: sandy_root_config_dir_custom_yml
test:
usernameV2: test_root_config_dir_custom_yml hello:
usernameV2: sandy_root_config_dir_custom_yml
username: sandy_root_config_dir_custom_yml
test:
usernameV2: hello_root_config_dir_custom_yml
username: test_root_config_dir_custom_yml

最终restful 接口返回值如下:

{
"usernameV2": null,
"testUsernameV2": "test_root_config_dir_custom_yml",
"username": null,
"testUsername": "test_classpath_applicaiton_properties",
"helloTestUsernameV2": "test_root_config_dir_custom_propeties"
}

2、application.properties  和 application.yml 共存时

(1) 当仅在 src/main/resources 存在这两个文件时

package com.example.demo.config.dto;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Component
public class ApplicationPropertiesV1 {
@Value("${day.username}")
private String helloUsername;
@Value("${day.test.username}")
private String helloTestUsername; public String getHelloUsername() {
return helloUsername;
} public void setHelloUsername(String helloUsername) {
this.helloUsername = helloUsername;
} public String getHelloTestUsername() {
return helloTestUsername;
} public void setHelloTestUsername(String helloTestUsername) {
this.helloTestUsername = helloTestUsername;
} }
@GetMapping("/application")
public ApplicationPropertiesV1 findApplicationInject(){
return applicationPropertiesV1;
}

src/main/resources/applicaiton.properties

day.username=day_sandy_classpath_applicaiton_properties
day.test.username=day_test_classpath_applicaiton_properties

src/main/resources/applicaiton.yml

day:
username: day_sandy_classpath_applicaiton_yml
test:
username: test_classpath_applicaiton_yml

restful 接口调用结果

{
"helloUsername": "day_sandy_classpath_applicaiton_yml",
"helloTestUsername": "test_classpath_applicaiton_yml"
}

说明:

同在类路径下,properties 的 优先级 高于 yml,同名key以前者中的值为准;

   (2) application 全局配置文件在不同目录下:

SpringBoot配置文件可以放置在多种路径下,不同路径下的配置优先级有所不同。
可放置目录(优先级从高到低)

file:./config/ (当前项目路径config目录下);
    file:./ (当前项目路径下);
    classpath:/config/ (类路径config目录下);
    classpath:/ (类路径config下).

优先级由高到底,高优先级的配置会覆盖低优先级的配置;出现同名 key 的时候,以优先级高的目录中的配置文件中的值为准;
SpringBoot会从这四个位置全部加载配置文件并互补配置;

(2) 中的说明参考链接:https://blog.csdn.net/IT_faquir/article/details/80869578

(3) application.properties 在依赖包也存在

本工程中的 application.properties 优先级高于 依赖包中的该配置文件,加载时仅加载本工程中的该配置文件,依赖包中的不会加载。

三:总结

配置的方式主要有以下几种:

  • 来自 applicaiton开头的配置文件的配置 (properties 或 yml 结尾);

a) properties 的配置高于 yml 的配置,两个文件均会加载,但是 同名 key 的以 properties 的值为准;

b) 依赖包也存在 application配置文件,同样名称的配置文件 仅会加载一处,本工程中存在,加载本工程中的配置文件,否则加载依赖包中的配置文件;

c) application 配置文件放置在本工程不同位置,均会加载,但是对于同名key,优先级从高到低如下:

i) file:./config/ (当前项目路径config目录下);
                       ii) file:./ (当前项目路径下);
                       iii) classpath:/config/ (类路径config目录下);
                       iiii) classpath:/ (类路径config下).

  • @propertySource 配置的引入外部文件的配置 文件(非application开头的文件,文件可以存储在类上下文环境中,也可以是在文件系统下,如:在项目工程根目录下),可以配置加载多个外部配置文件,后加载的可以覆盖前面覆盖的同名 key;
  • @Bean 自定义加载 的 PropertySourcesPlaceholderConfigurer,可以加载多个外部配置文件。后加载的可以覆盖前面覆盖的同名 key;

当遇上同名key的时候,以上三种方式 是从 优先级高到低排列的,同名 key以优先级高的配置方式为准。

 四:未研究问题

(1) 在上述覆盖配置的场景下,更多的是介绍本工程下出现配置文件出现在不同目录下,若依赖的包中也存在 application.yml配置 或 同文件名的配置文件时,又是怎样加载配置文件的?以及怎样覆盖同名配置项的?

spring boot 学习笔记(三)之 配置的更多相关文章

  1. Spring Boot学习笔记(六)mybatis配置多数据源

    application.properties #数据库配置 #数据源类型 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # ...

  2. Spring Boot学习笔记(三)实现热部署

    pom文件中添加如下依赖即可 <dependency> <groupId>org.springframework.boot</groupId> <artifa ...

  3. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  4. Spring Boot学习笔记2——基本使用之最佳实践[z]

    前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...

  5. spring boot学习笔记

    spring boot 是什么 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程. spring boot采用了“约定优于配置” ...

  6. 我的第一个spring boot程序(spring boot 学习笔记之二)

    第一个spring boot程序 写在前面:鉴于spring注解以及springMVC的配置有大量细节和知识点,在学习理解之后,我们将直接进入spring boot的学习,在后续学习中用到注解及其他相 ...

  7. Spring Boot学习笔记---Spring Boot 基础及使用idea搭建项目

    最近一段时间一直在学习Spring Boot,刚进的一家公司也正好有用到这个技术.虽然一直在学习,但是还没有好好的总结,今天周末先简单总结一下基础知识,等有时间再慢慢学习总结吧. Spring Boo ...

  8. spring boot 学习笔记(二)之打包

    一.叙述 spring boot 在 pom 中可以配置成  packaging 为 jar ,这样打包出来的就是一个 jar 包,可以通过 Java 命令直接运行, Java 命令为: java - ...

  9. Spring Boot学习笔记——Spring Boot与Redis的集成

    一.添加Redis缓存 1.添加Redis起步依赖 在pom.xml中添加Spring Boot支持Redis的依赖配置,具体如下: <dependency> <groupId> ...

  10. Spring Boot学习笔记——Spring Boot与MyBatis的集成(项目示例)

    1.准备数据库环境 # 创建数据库 CREATE DATABASE IF NOT EXISTS zifeiydb DEFAULT CHARSET utf8 COLLATE utf8_general_c ...

随机推荐

  1. 教你快速写一个EventBus框架

    前言EventBus相信大多数人都用过,其具有方便灵活.解耦性强.体积小.简单易用等优点,虽然现在也有很多优秀的替代方案如RxBus.LiveDataBus等,但不可否认EventBus开创了消息总线 ...

  2. ELK(elasticsearch+logstash+kibana)入门到熟练-从0开始搭建日志分析系统教程

    #此文篇幅较长,涵盖了elk从搭建到运行的知识,看此文档,你需要会点linux,还要看得懂点正则表达式,还有一个聪明的大脑,如果你没有漏掉步骤的话,还搭建不起来elk,你来打我. ELK使用elast ...

  3. C++ STL——set和multiset

    目录 一 set和multiset 二 对组pair 注:原创不易,转载请务必注明原作者和出处,感谢支持! 注:内容来自某培训课程,不一定完全正确! 一 set和multiset set和multis ...

  4. 几句简单的python代码完成周公解梦功能

    <周公解梦>是靠人的梦来卜吉凶的一本于民间流传的解梦书籍,共有七类梦境的解述.这是非常传统的中国文化体系的一部分,但是如何用代码来获取并搜索周公解梦的数据呢?一般情况下,要通过爬虫获取数据 ...

  5. vlc的流输出功能

    vlc的流输出功能 流输出功能,可以将vlc读取到的流,输出到文件或者通过网络发送,客户端可以使用http.rtp.rtsp等协议访问,还可以进行转码等操作. 参考http://wiki.videol ...

  6. Python统计分析可视化库seaborn(相关性图,变量分布图,箱线图等等)

    Visualization of seaborn  seaborn[1]是一个建立在matplot之上,可用于制作丰富和非常具有吸引力统计图形的Python库.Seaborn库旨在将可视化作为探索和理 ...

  7. 红队(red team)

    红队资源相关 https://threatexpress.com/redteaming/resources/ 红队相关技术 https://github.com/bluscreenofjeff/Red ...

  8. Java 基础篇之泛型

    背景 在没有泛型前,一旦把一个对象丢进集合中,集合就会忘记对象的类型,把所有的对象都当成 Object 类型处理.当程序从集合中取出对象后,就需要进行强制类型转换,这种转换很容易引起 ClassCas ...

  9. 【Web网站服务器开发】apache和tomcat 阿帕奇和汤姆猫

    经常在用apache和tomcat等这些服务器,可是总感觉还是不清楚他们之间有什么关系,在用tomcat的时候总出现apache,总感到迷惑,到底谁是主谁是次,因此特意在网上查询了一些这方面的资料,总 ...

  10. Linux 脚本

    1.理解Linux Shell和基本Shell脚本语言的小贴士(一) http://blog.jobbole.com/63952/ ------伯乐在线