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...

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

相关推荐
激流丶14 分钟前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue18 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
让学习成为一种生活方式34 分钟前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
晨曦_子画40 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
假装我不帅1 小时前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
神仙别闹1 小时前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
Heavydrink1 小时前
HTTP动词与状态码
java
ktkiko111 小时前
Java中的远程方法调用——RPC详解
java·开发语言·rpc