SpringBoot教程(四) | SpringBoot中的配置文件

SpringBoot教程(四) | SpringBoot中的配置文件

4.1 关于yml 和 properties的写法问题

上文我中我们提到,spring中常用的配置文件有yml 和 properties 两种,都是以application来命名的,通常放到resources文件夹下。yml是使用缩进来体现层级管理的, 而properties 中是以. 的形式体现。二者没啥区别,根据个人的使用习惯来进行选择即可。目前来说用的比较多的还是yml 形式的。为什么呢,因为properties 可能会有很多冗余的书写,相对于yml来说,不够简洁。我们具体体会一下。

比如我们要配置两个变量 server.port=9090 server.name=management

properties写法:

properties 复制代码
properties复制代码server.port=9090  
server.name=management

yml写法:

yml 复制代码
yml复制代码server:
  port: 9090
  name: management

相比之下,yaml的写法更加的简洁一下。 properties的写法层级关系不够明显。多的时候,会显得比较乱。

4.2 关于配置文件的位置问题

位置的问题,我们只提到了放到resources 文件夹的下面,其实就是对应的classPath下,因为最终打包之后,java 和 resources 下的所有文件都在classPath之下。其实springBoot 的配置文件总共可以放到四个地方,优先级如下:

  1. 项目根目录下的config目录中
  2. 项目根目录下
  3. classPath下的config目录中
  4. classpath 目录下

优先级从上到下,当出现多个的时候,以优先级高的为准。我们放到了resources目录下,其实相当于用的是上面提到的4.

那我们可以验证一下。我们在resources下面创建一个config文件夹,在创建一个application.yml的配置文件,通过配置端口号的方式看看谁生效了,也就知道谁的优先级高了。

最终发现,启动的是6666端口,代表3的优先级是高于4的。(properties和yml同级优先级的问题昨天已经说过了)

同样的方式我们也可以验证一下1和2.这里就不带大家验证了。

对于1,2 的方式,其实在我们运维的时候是有用的。这里个大家提一下。

通常我们springBoot项目部署的时候,都是打成一个jar包,然后放到对应的机器上,通过java -jar的方式进行启动。由于打成了jar包,所有相应的配置文件也打到了jar包了,这个时候发现我们想要修改里边的配置是非常困难的,尤其是在得不到源码的情况下。那么怎么办呢,我们可以把这个包拷贝到本地环境,把里面的配置文件提取出来,然后把需要修改的配置修改一下,然后在服务器上jar包的路径下创建一个config文件夹,再把修改后的配置文件放到这个文件夹中,重新启动项目,这个时候,修改后的配置文件就可以替换原来的配置文件生效了。这里就是利用了不同位置配置文件优先级不同的情况。

4.3 关于不同环境不同配置的解决方案

配置文件的基本用法我们已经说完了,就是application.yml 或者是 application.properties ,我们可以在配置文件中配置我们需要的信息,比如数据库的连接等。但实际开发中我们往往遇到这样的情况,就是我们可能会有多套环境,比如有开发环境,有测试环境,还有生产环境,每套环境中肯定都有一套配置,并且他们之间的配置内容是不一样的,比如开发环境的数据库地址,生产环境的数据库地址肯定都是不一样的。那么我们的程序在发布到不同环境的时候,难道每次都要修改配置文件里的内容么,这样的话肯定太麻烦了,而springBoot为我们提供了合理的解决方案。

怎么解决呢,那就是使用多套配置文件。比如开发环境,那么我们就创建一个application-dev.yml , 测试环境我们就创建一个application-test.yml. 生产环境我们就创建一个 application-prod.yml的文件,当然也可以使用properties 类型的文件。而对于dev. test. prod这样的名称我们是可以自己来确定的,可以根据自己的实际情况来取。那么既然有了多套配置文件,我们该如何让他生效呢。 springBoot优先加载的肯定还是application.yml,我们只需在这个配置文件中来指定让谁生效即可。

application-dev.yml

yml 复制代码
yml复制代码spring: 
  datasource:
      url: jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai

application-test.yml

yml 复制代码
yml复制代码spring: 
  datasource:
      url: jdbc:mysql://192.168.1.1:3306/test?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai

如何指定呢,使用 spring.profiles.active

application.yml

yaml 复制代码
yaml复制代码spring:
    profiles:
        active: dev

这里指定了dev生效,那么就会去加载 application-dev.yml配置文件中的内容。如果想让application-test.yml文件生效,就把dev改为test即可。

但是问题是我也不能每次都来修改application.yml啊,我发布dev的时候,这个配置改成dev打包,发布测试环境的时候,改成test打包,虽然比之前简单了一些但还是很麻烦。怎么办呢,其实一般情况我们是不需要修改这个值的,比如说这个值现在配置的是dev, 我去发布测试环境,就有相同的jar包只需要在启动命令里指定即可:

bash 复制代码
bash
复制代码java -jar xxx.jar --spring.profiles.active=test

这是因为启动命令中的参数的优先级是高于项目中的配置文件的,所以这样就万事大吉了。

除了这种方式之外,我们也可以通过配置中心来解决这个问题,当然这就是后话了。

4.4 读取配置文件中的值

除了上面的一些spring预设的配置,有的时候我们也把一些经常需要修改的值放到配置文件中,方便我们进行修改。那么配置文件中的值,我们在程序当中应该如何获取呢,我们来研究一下。

方式一: @Value注解

Spring中的@Value注解,可以帮助我们读取到配置文件中的值。

application.yml

yml 复制代码
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中测试:

java 复制代码
java复制代码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中提供的一个变量,用来封装环境信息数据,我们也可以这个文件中获取配置文件中的内容。使用方式如下。

java 复制代码
java复制代码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

我们在config文件夹下创建一个类,用于接收配置文件中的这些内容。类写法如下

java 复制代码
java复制代码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中的配置内容相对应。

封装好了之后如何使用的,使用的方式差不多。

java 复制代码
java复制代码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";
    }
}

除此之外,这种方式还可以用来获取数组或集合。我们在配置文件中直接添加内容:

yml 复制代码
yml复制代码third:
  weather:
    url: http://www.baidu.com
    port: 8080
    username: test
    cities:
      - 北京
      - 上海
      - 广州
    list[0]: aaa
    list[1]: bbb
    list[2]: ccc

在配置类中添加数组和集合的属性

java 复制代码
java复制代码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 提示我们添加一个依赖。

xml 复制代码
xml复制代码<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

添加完以后,刷新下就可以了,加了这个依赖后,可以弹出提示信息。具体参见: blog.csdn.net/liangjiabao...

好了关于配置文件的内容,先介绍这么多,应该足够使用了。

相关推荐
Asthenia04121 分钟前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom3 分钟前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
Asthenia04121 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom2 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide2 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04123 小时前
Spring 启动流程:比喻表达
后端