SpringBoot教程(四) | SpringBoot中的配置文件
转载
一缕82年的清风
大佬的文章(仅仅供个人学习用):
SpringBoot教程(四) | SpringBoot中的配置文件
一、 关于yml 和 properties的写法问题
上文我中我们提到,spring中常用的配置文件有yml 和 properties 两种,都是以application来命名的,通常放到resources文件夹下。yml是使用缩进来体现层级管理的, 而properties 中是以. 的形式体现。二者没啥区别,根据个人的使用习惯来进行选择即可。目前来说用的比较多的还是yml 形式的。为什么呢,因为properties 可能会有很多冗余的书写,相对于yml来说,不够简洁。我们具体体会一下。
比如我们要配置两个变量 server.port=9090 server.name=management
properties写法:
server.port=9090
server.name=management
yml写法:
server:
port: 9090
name: management
相比之下,yaml的写法更加的简洁一下。 properties的写法层级关系不够明显。多的时候,会显得比较乱。
二、 关于配置文件的位置问题
位置的问题,我们只提到了放到resources 文件夹的下面,其实就是对应的classPath下,因为最终打包之后,java 和 resources 下的所有文件都在classPath之下。其实springBoot 的配置文件总共可以放到四个地方,优先级如下:
- 项目根目录下的config目录中
- 项目根目录下
- classPath下的config目录中
- classpath 目录下
优先级从上到下,当出现多个的时候,以优先级高的为准。我们放到了resources目录下,其实相当于用的是上面提到的4.
那我们可以验证一下。我们在resources下面创建一个config文件夹,在创建一个application.yml的配置文件,通过配置端口号的方式看看谁生效了,也就知道谁的优先级高了。
最终发现,启动的是6666端口,代表3的优先级是高于4的。(properties和yml同级优先级的问题昨天已经说过了)
同样的方式我们也可以验证一下1和2.这里就不带大家验证了。
对于1,2 的方式,其实在我们运维的时候是有用的。这里个大家提一下。
通常我们springBoot项目部署的时候,都是打成一个jar包,然后放到对应的机器上,通过java -jar的方式进行启动。由于打成了jar包,所有相应的配置文件也打到了jar包了,这个时候发现我们想要修改里边的配置是非常困难的,尤其是在得不到源码的情况下。那么怎么办呢,我们可以把这个包拷贝到本地环境,把里面的配置文件提取出来,然后把需要修改的配置修改一下,然后在服务器上jar包的路径下创建一个config文件夹,再把修改后的配置文件放到这个文件夹中,重新启动项目,这个时候,修改后的配置文件就可以替换原来的配置文件生效了。这里就是利用了不同位置配置文件优先级不同的情况。
三、 关于不同环境不同配置的解决方案
配置文件的基本用法我们已经说完了,就是application.yml 或者是 application.properties ,我们可以在配置文件中配置我们需要的信息,比如数据库的连接等。但实际开发中我们往往遇到这样的情况,就是我们可能会有多套环境,比如有开发环境,有测试环境,还有生产环境,每套环境中肯定都有一套配置,并且他们之间的配置内容是不一样的,比如开发环境的数据库地址,生产环境的数据库地址肯定都是不一样的。那么我们的程序在发布到不同环境的时候,难道每次都要修改配置文件里的内容么,这样的话肯定太麻烦了,而springBoot为我们提供了合理的解决方案。
怎么解决呢,那就是使用多套配置文件。比如开发环境,那么我们就创建一个application-dev.yml , 测试环境我们就创建一个application-test.yml. 生产环境我们就创建一个 application-prod.yml的文件,当然也可以使用properties 类型的文件。而对于dev. test. prod这样的名称我们是可以自己来确定的,可以根据自己的实际情况来取。那么既然有了多套配置文件,我们该如何让他生效呢。 springBoot优先加载的肯定还是application.yml,我们只需在这个配置文件中来指定让谁生效即可。
application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
application-test.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
如何指定呢,使用 spring.profiles.active
application.yml
spring:
profiles:
active: dev
这里指定了dev生效,那么就会去加载 application-dev.yml配置文件中的内容。如果想让application-test.yml文件生效,就把dev改为test即可。
但是问题是我也不能每次都来修改application.yml啊,我发布dev的时候,这个配置改成dev打包,发布测试环境的时候,改成test打包,虽然比之前简单了一些但还是很麻烦。怎么办呢,其实一般情况我们是不需要修改这个值的,比如说这个值现在配置的是dev, 我去发布测试环境,就有相同的jar包只需要在启动命令里指定即可:
java -jar xxx.jar --spring.profiles.active=test
这是因为启动命令中的参数的优先级是高于项目中的配置文件的,所以这样就万事大吉了。
除了这种方式之外,我们也可以通过配置中心来解决这个问题,当然这就是后话了。
四、 读取配置文件中的值
除了上面的一些spring预设的配置,有的时候我们也把一些经常需要修改的值放到配置文件中,方便我们进行修改。那么配置文件中的值,我们在程序当中应该如何获取呢,我们来研究一下。
方式一: @Value注解 (最常用)
(1)@Value注解默认会尝试从application.properties或application.yml文件中读取属性值。这是Spring Boot的自动配置特性之一,它会在应用启动时自动加载位于src/main/resources目录下的这些文件。
(2)如果需要读取除application.properties或application.yml之外的其他配置文件中的值,可以通过@PropertySource注解来指定这些文件的路径。@PropertySource可以加载classpath下的文件,也可以加载文件系统中的文件。
application.yml
server:
port: 9090
third:
weather:
url: http://www.baidu.com
port: 8080
username: test
比如我们把一个第三方获取天气的地址配置到了配置文件中,我们需要在程序中获取这个值怎么写呢,通常我们要在能够被spring管理的类(也就是所说的bean)中才能使用@Value注解,所谓被spring管理的bean指的就是首先位于被扫描的包里,并且有spring标识的注解,如@Controller,@Service,@Component等。
我们就在我们之前写的FirstController中测试:
package com.lsqingfeng.springboot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @className: FirstController
* @description: 第一个Controller
* @author: sh.Liu
* @date: 2022-01-10 15:21
*/
@RestController
public class FirstController {
@Value("${third.weather.url}")
private String weatherUrl;
@RequestMapping("/hello")
public String helloWorld(){
System.out.println("获取到的天气地址为:" + weatherUrl);
return "hello world";
}
}
这样当我们访问这个接口的时候,就会打印出来获取到的值。
获取成功。
方式二: 使用Environment接口
Envionment 类是Spring中提供的一个接口,用来封装环境信息数据,我们也可以这个文件中获取配置文件中的内容。使用方式如下。
package com.lsqingfeng.springboot.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* @className: FirstController
* @description: 第一个Controller
* @author: sh.Liu
* @date: 2022-01-10 15:21
*/
@RestController
public class FirstController {
@Autowired
private Environment env;
@RequestMapping("/hello")
public String helloWorld(){
// 使用env 对象获取配置文件中的值
String weatherUrl = env.getProperty("third.weather.url");
System.out.println("获取到的天气地址为:" + weatherUrl);
return "hello world";
}
}
通过注入Environment接口,调用getProperty,传入相应的key来获取对应的结果。
方式三: 将配置文件中的内容封装成一个javaBean,再让这个bean通过@ConfigurationProperties获取
我们在config文件夹下创建一个类,用于接收配置文件中的这些内容。类写法如下
package com.lsqingfeng.springboot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @className: ThirdWeatherConfig
* @description: 三方天气变量封装
* @author: sh.Liu
* @date: 2022-01-12 10:33
*/
@Configuration
@ConfigurationProperties(prefix = "third.weather")
public class ThirdWeatherConfig {
private String url;
private Integer port;
private String username;
public void setUrl(String url) {
this.url = url;
}
public void setPort(Integer port) {
this.port = port;
}
public void setUsername(String username) {
this.username = username;
}
public String getUrl() {
return url;
}
public Integer getPort() {
return port;
}
public String getUsername() {
return username;
}
}
这里要注意,类中的属性名称要和配置文件中的名称去掉前缀后保持一致。
还有就是目前我们没有指定配置文件的名称,因为他是默认读取application.yml中的内容,
如果我们配置内容没有在application.yml中,那么需要在类上指定文件的位置:使用如下注解:
@PropertySource("classpath:config/my.yml")
这就代表这个类中数据是要和 config/my.yml中的配置内容相对应。
封装好了之后如何使用的,使用的方式差不多。
package com.lsqingfeng.springboot.controller;
import com.lsqingfeng.springboot.config.ThirdWeatherConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @className: FirstController
* @description: 第一个Controller
* @author: sh.Liu
* @date: 2022-01-10 15:21
*/
@RestController
public class FirstController {
@Value("${third.weather.url}")
private String weatherUrl;
@Autowired
private Environment env;
@Autowired
private ThirdWeatherConfig thirdWeatherConfig;
@RequestMapping("/hello")
public String helloWorld(){
// 使用封装好的对象获取内容
String weatherUrl = thirdWeatherConfig.getUrl();
System.out.println("获取到的天气地址为:" + weatherUrl);
return "hello world";
}
}
除此之外,这种方式还可以用来获取数组或集合。我们在配置文件中直接添加内容:
third:
weather:
url: http://www.baidu.com
port: 8080
username: test
cities:
- 北京
- 上海
- 广州
list[0]: aaa
list[1]: bbb
list[2]: ccc
在配置类中添加数组和集合的属性
package com.lsqingfeng.springboot.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @className: ThirdWeatherConfig
* @description: 三方天气变量封装
* @author: sh.Liu
* @date: 2022-01-12 10:33
*/
@Configuration
@ConfigurationProperties(prefix = "third.weather")
public class ThirdWeatherConfig {
private String url;
private Integer port;
private String username;
private String[] cities;
private List<String> list;
public void setUrl(String url) {
this.url = url;
}
public void setPort(Integer port) {
this.port = port;
}
public void setUsername(String username) {
this.username = username;
}
public String getUrl() {
return url;
}
public Integer getPort() {
return port;
}
public String getUsername() {
return username;
}
public String[] getCities() {
return cities;
}
public void setCities(String[] cities) {
this.cities = cities;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}
获取值:
再说一个小知识点。我们用来接收注解的javaBean上有一个警告:
这个问题怎么解决是,其实是SpringBoot 提示我们添加一个依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
添加完以后,刷新下就可以了,加了这个依赖后,可以弹出提示信息。具体参见: blog.csdn.net/liangjiabao…
好了关于配置文件的内容,先介绍这么多,应该足够使用了。