SpringBoot读取配置文件(重点)

SpringBoot分别提供3中方式读取项目的application.properties配置文件的内容。这个方式分别为:Environment类、@Value注解以及@ConfigurationProperties注解。

你必须要知道的事情:下面提供的三种方式,都可以拿到配置文件的信息,不要纠结那种方式好与坏。你爱用中方式就用那种方式。只要能解决问题就可以了。

1、Environment

Environment是用来读取应用程序运行时的环境变量的类,可以通过key-value的方式读取application.properties和系统环境变量,命令行输入参数,系统属性等,具体如下:

在application.yml文件定义如下:

# 属性配置类的
server:
  port: 8082

spring:
  main:
    banner-mode: console

# 自定义
alipay:
  pay:
    appid: 123456
    notify: http://www.xxx.com

定义读取的类如下:

package com.kuangstudy.web.properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * Description:
 * Author: yykk Administrator
 * Version: 1.0
 * Create Date Time: 2021/12/11 21:25.
 * Update Date Time:
 *
 * @see
 */
@RestController
public class ReadPropertiesEnvironment {

    @Autowired
    private Environment environment;


    @GetMapping("/read/file")
    public Map<String,Object> readInfo(){
        Map<String,Object> map = new HashMap<>();
        map.put("port",environment.getProperty("server.port"));
        map.put("appid",environment.getProperty("alipay.pay.appid"));
        map.put("notify",environment.getProperty("alipay.pay.notify"));
        map.put("javaversion",environment.getProperty("java.version"));
        map.put("javahome",environment.getProperty("JAVA_HOME"));
        map.put("mavenhome",environment.getProperty("MAVEN_HOME")); 
        return  map;
    }

    public static void main(String[] args) {
        Properties properties = System.getProperties();
        Set<String> strings = properties.stringPropertyNames();
        for (String string : strings) {
            System.out.println(string+"===>"+properties.get(string));
        }

    }

}

在浏览器访问

http://localhost:8082/read/file

在这里插入图片描述

2、@Value

使用@Value注解读取配置文件内容,具体如下:

package com.kuangstudy.web.properties;

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.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * Description:
 * Author: yykk Administrator
 * Version: 1.0
 * Create Date Time: 2021/12/11 21:25.
 * Update Date Time:
 *
 * @see
 */
@RestController
public class ReadPropertiesValue {

    @Value("${server.port}")
    private Integer port;
    @Value("${alipay.pay.appid}")
    private String appid;
    @Value("${alipay.pay.notify}")
    private String notify;
    @Value("${java.version}")
    private String javaVersion;
    @Value("${JAVA_HOME}")
    private String javaHome;
    @Value("${MAVEN_HOME}")
    private String mavenHome;


    @GetMapping("/read/value")
    public Map<String, Object> readInfo() {
        Map<String, Object> map = new HashMap<>();
        map.put("port", port);
        map.put("appid", appid);
        map.put("notify", notify);
        map.put("javaversion", javaVersion);
        map.put("javahome", javaHome);
        map.put("mavenhome", mavenHome);
        return map;
    }

}

浏览器如下:
在这里插入图片描述

结论:其实@Value底层就是Environment.java

3、@ConfigurationProperties (属性配置类的底层原理)

使用@ConfigurationProperties首先建立配置文件与对象的映射关系,然后在控制器方法中使用@Autowired注解将对象注入。具体如下:

我们指定:@SpringBootApplication 注解是一个复合注解:其中有两个注解是和配置类和属性配置类有关:如下:

1、@SpringBootConfiguration :对@Configuration注解的升级版本。一般用来扩展和覆盖内部的配置的。自定义starter的时候使用的一种机制(springboot提供让开发人员扩展使用的一直机制,因为官方提供配置类不可能满足未来所有业务场景和需求,或者一些新的技术的诞生,springboot团队是不可能马上就开发所谓starter,这个时候就只能去扩展或者自定义,未来所讲的starter其实就通过配置类和属性配置完成这个过程其中使用的原理就是:@SpringBootConfiguration+@Bean 或者 @Configuration + @Bean)

2、@EnableAutoConfiguration:去加载springBoot官方提供的starter包提供的配置类和属性配置类。官方提供了一系列的starters的依赖,这些依赖分别方在:spring-boot-autoconfigure-2.5.7.jar
在这里插入图片描述

这个思想:java9中新特性:SPI,把项目中一些类的初始化放在一个文件中,然后去加载和读取这个文件,将其实例化的过程。

每个配置类一般都搭配一个属性配置类:

  • DataSourceConfiguration + DataSourceProperties
  • JacksonAutoConfiguration + JacksonProperties
  • KafkaAutoConfiguration + KafkaProperties

属性配置类的的作用就是让你去扩展和动态修改属性值的一个机制,如果没有这个机制其实starter其实毫无意义。比如:我的:kafka: 158.12.41.41:9092 内部:localhost:9092 .

同时告诉我们一个道理:每天在全局配置文件中配置其实都是在给starter属性配置类在进行赋值。也是就说没个配置都会对应对一个属性配置类。每个值都对应属性配置类的属性。比如:

server.port=8080 对应的配置类:ServerProperties port就是属性:port

ServerProperties serverp = new ServerProperties();
serverp.setPort(8080)

一句话:配置文件在每天配置,其实背后都有一个类,定义值其实都是给类的属性赋值。你就想象成调用set方法。只不过这个过程创建对象的过程,和赋值你过程看不到而已,但是绝对是java基础,创建对象给属性赋值。

4、为什么要用属性配置

传统的代码编写就通过耦合的方式编写如下:

    @GetMapping("/alipay")
    public String alipay(){
        String appid = "2021003100625328";
        String mkey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC9kGK4VMbYm";
        String ckey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5i5LhEtDZw6Q6mUxkC5f6sAvZm9OncAkRXwfoBdDeKk";
        String callbackurl = "https://www.txnh.net/api/alipay/returnUrl";
        String charset = "utf-8";
        log.info("你支付是的appid:{},{},{},{}",appid, ckey,mkey,callbackurl,charset);
        return "success";
    }

  • 上面的代码没有错误的,是正确的
  • 上面是耦合的,如果我换了公司,换企业就必须重新在代码进行修改,就不方便进行调整。

5、使用@Value的方式进行定义

第一步:在application.yml文件中自定义属性:

# 自定义属性
ksd:
  alipay:
    appid: 2021003100625328
    mkey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC9kGK4VMbYm
    ckey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5i5LhEtDZw6Q6mUxkC5f6sAvZm9OncAkRXwfoBdDeKk
    callbackurl: https://www.txnh.net/api/alipay/returnUrl
    charset: utf-8

第二步:在代码中使用@Value的方式进行获取全局配置文件中对应的值如下:

package com.kuangstudy.web.properties;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.MacSpi;

@RestController
@Slf4j
public class AlipayController {

    @Value("${ksd.alipay.appid}")
    private String appid;
    @Value("${ksd.alipay.mkey}")
    private String mkey;
    @Value("${ksd.alipay.ckey}")
    private String ckey;
    @Value("${ksd.alipay.callback}")
    private String callbackurl;
    @Value("${ksd.alipay.charset}")
    private String charset;


    @GetMapping("/alipay")
    public String alipay(){
        log.info("你支付是的appid:{},{},{},{}",appid, ckey,mkey,callbackurl,charset);
        return "success";
    }
}

第三步:在浏览器访问如下

http://localhost:8083/alipay
在这里插入图片描述

  • 通过上面可以很清楚看到@Value可以读取全局配置文件对应的属性的值。
  • 好处:封装和统一管理,解决耦合性。
  • 缺点1:不具备面向对象特征,如果属性过多,而且有一类的很难区分,
  • 缺点2:如果@Value(key)使用的key如果在配置文件中没有定义,直接报错

6、springboot官方提供的starter配置类为什么不用@Value

  • 属性太多,而且用@Value不具备面向对象的特征和行为,所以就用@ConfigurationProerpties去取代@Value的方式。
  • @Value有毛病,就是无法在全部配置文件中进行自动提示

7、springBoot取而代之的是@Configuration + @ConfigurationProperties

  • 具有面向对象的特征

  • 可以在代码中自动提示

  • 维护起来很方便。在配置文件也可以很方便的控制和提示

    具体实现步骤:

第一步:在application.yml自定义支付属性

# 自定义属性
ksd:
  alipay:
    appid: 2021003100625328
    mkey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC9kGK4VMbYm
    ckey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5i5LhEtDZw6Q6mUxkC5f6sAvZm9OncAkRXwfoBdDeKk
    callback: https://www.txnh.net/api/alipay/returnUrl
    charset: utf-8

第二步:定义一个属性配置类如下:

package com.kuangstudy.web.properties;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Description:
 * Author: yykk Administrator
 * Version: 1.0
 * Create Date Time: 2021/12/14 20:53.
 * Update Date Time:
 *
 * @see
 */
@ConfigurationProperties(prefix = "ksd.alipay")//这个注解是用找到类
@Data
public class AlipayProperties {
    private String appid;
    private String mkey;
    private String ckey;
    private String callback;
    private String charset;
}

  • @ConfigurationProperties(prefix = “ksd.alipay”)//这个注解的作用是:找到类
  • prefix = “ksd.alipay” 前缀未来可以在全局配置文件中进行自动提示。

第三步:属性配置类必须找到一个配置类进行注册如下:

package com.kuangstudy.web.properties;

import lombok.Data;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * Description:
 * Author: yykk Administrator
 * Version: 1.0
 * Create Date Time: 2021/12/14 20:53.
 * Update Date Time:
 *
 * @see
 */
// 用配置类去注册:属性配置类
@EnableConfigurationProperties(AlipayProperties.class)
@SpringBootConfiguration
public class AlipayConfiguration {

}

建议:一个属性配置类 – 找到自己对应配置类进行注册, @EnableConfigurationProperties(AlipayProperties.class)

问:可以在启动类注册吗?可以,因为启动类本身也是一个配置类,但是不推荐。考虑后续的维护以及可插拔性。

8、总结

  • 在开发中不要纠结到底使用那种好那种坏,你可以解决业务问题就可以了
  • 如果属性仅仅就1~3个其实就用@Value就可以。但是如果很多还是建议大家使用@ConfigurationProperties + @Configuration机制会更好,可以更加清晰底层原来在做什么事情。
  • 这也是为什么底层不用@Value的原因。 @Configuration + @Value 这种理论是可以,但是有毛病不能在全局配置文件中进行自动提示。

9、关于属性配置类的自动提示的问题

在这里插入图片描述

第一步:pom.xml中增加配置

<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

第二步:关闭所有

  • 把idea打开的所有的类和全局配置文件全部关闭。(很重要)

  • 然后打开maven的控制,执行clean和compile即可
    在这里插入图片描述

  • 重新开applicaiton.yml文件进行查看是否自动提示,如果可以就说明生效了:
    在这里插入图片描述

10、@PropertySource(不推荐)

开发者希望读取项目的其他配置文件,而不是全局配置文件中的application.properties,该如何实现呢?可以使用@PropertySource注解找到项目的其他的配置文件。

方式:@PropertySource + @Value

具体如下:

定义两个属性配置文件a.yml和b.yml

a.yml

user.nickname: zhangsan

b.yml

user.age: 32

第二步:定义类

package com.kuangstudy.web.properties;

import com.kuangstudy.web.properties.config.AlipayProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
@PropertySource({"classpath:a.yml","classpath:b.yml"})
public class AlipayController3 {

    @Value("${user.nickname}")
    private String userName;
    @Value("${user.age}")
    private String userage;

    @GetMapping("/alipay3")
    public String alipay3(){
        log.info("你支付是的:{},{}",userName,userage);
        return "success";
    }
}

第三步:访问测试

http://localhost:8083/alipay3
在这里插入图片描述

总结:

  • 这种@PropertySource机制是一种扩展属性配置文件的机制。
  • 一般不建议大家去使用,学习目的是未来能看得懂别人写的逻辑和代码。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值