【微服务】spring读取配置文件多种方式深入详解

目录

一、前言

二、java配置文件介绍

[2.1 java配置文件产生原因](#2.1 java配置文件产生原因)

[2.2 项目使用配置文件好处](#2.2 项目使用配置文件好处)

[2.3 springboot项目配置文件的必要性](#2.3 springboot项目配置文件的必要性)

[2.4 微服务架构下配置文件使用场景](#2.4 微服务架构下配置文件使用场景)

三、java读取配置文件常用方法

[3.1 使用Properties类读取配置文件](#3.1 使用Properties类读取配置文件)

[3.1.1 使用getResourceAsStream读取](#3.1.1 使用getResourceAsStream读取)

[3.1.2 使用getClassLoader读取](#3.1.2 使用getClassLoader读取)

[3.2 使用ClassLoader读取配置文件](#3.2 使用ClassLoader读取配置文件)

四、spring中读取配置文件常用方法

[4.1 使用ClassPathResource读取](#4.1 使用ClassPathResource读取)

[4.2 使用PropertyResourceBundle读取](#4.2 使用PropertyResourceBundle读取)

[4.3 使用PropertiesLoaderUtils 读取](#4.3 使用PropertiesLoaderUtils 读取)

[4.4 使用FileSystemResource读取](#4.4 使用FileSystemResource读取)

[4.4.1 使用FileSystemXmlApplicationContext读取](#4.4.1 使用FileSystemXmlApplicationContext读取)

[4.4.2 使用ClassPathXmlApplicationContext读取](#4.4.2 使用ClassPathXmlApplicationContext读取)

五、springboot读取配置文件常用方法

[5.1 使用@Value注解读取](#5.1 使用@Value注解读取)

[5.1.1 读取单个属性值](#5.1.1 读取单个属性值)

[5.1.2 使用默认值](#5.1.2 使用默认值)

[5.1.3 支持spel表达式](#5.1.3 支持spel表达式)

[5.2 @ConfigurationProperties 读取配置文件](#5.2 @ConfigurationProperties 读取配置文件)

[5.2.1 @ConfigurationProperties 读取配置文件原理](#5.2.1 @ConfigurationProperties 读取配置文件原理)

[5.2.2 @ConfigurationPropertiess补充点1](#5.2.2 @ConfigurationPropertiess补充点1)

[5.2.2 @ConfigurationProperties补充点2](#5.2.2 @ConfigurationProperties补充点2)

[5.2.3 @ConfigurationProperties补充点3](#5.2.3 @ConfigurationProperties补充点3)

[5.2.4 @ConfigurationProperties补充点4](#5.2.4 @ConfigurationProperties补充点4)

[5.3 使用 @PropertySource 读取配置文件](#5.3 使用 @PropertySource 读取配置文件)

[5.3.1 @PropertySource 读取配置文件原理](#5.3.1 @PropertySource 读取配置文件原理)

[5.4 使用Environment 读取配置文件](#5.4 使用Environment 读取配置文件)

[5.4.1 Environment读取配置文件原理](#5.4.1 Environment读取配置文件原理)

[5.5 使用原生方式读取配置文件](#5.5 使用原生方式读取配置文件)

六、springboot读取外部配置文件

[6.1 操作过程](#6.1 操作过程)

[6.1.1 搭建nacos服务](#6.1.1 搭建nacos服务)

[6.1.2 增加两个配置文件](#6.1.2 增加两个配置文件)

[6.1.3 引入pom依赖](#6.1.3 引入pom依赖)

[6.1.4 添加配置文件](#6.1.4 添加配置文件)

[6.1.4 增加测试接口读取配置](#6.1.4 增加测试接口读取配置)

七、写在文末


一、前言

在使用spring或springboot项目开发中,难免会涉及到读取配置文件的各种配置参数的情况,因为当项目的规模上去之后,在单个配置文件中维护所有的配置信息很难满足实际的需要,所以随着微服务技术的流行,用于统一管理和维护配置文件的第三方组件就随之产生了,譬如大家熟悉的nacos,appollo等。

二、java配置文件介绍

2.1 java配置文件产生原因

Java项目中配置文件的产生,是为了解决软件开发中的配置管理问题。随着软件系统规模的增大和复杂程度的提高,应用程序需要的配置信息也会变得越来越多。如果将这些配置信息硬编码在代码中,结果会导致代码可读性差、维护困难,并且修改配置信息需要重新编译和部署代码,不利于灵活性和可维护性。

因此,为了更好的管理和维护配置信息,开发人员开始将配置信息从代码中分离出来,存放到外部的配置文件中。这样,开发人员可以通过修改配置文件来调整应用程序的行为,而无需修改源代码。同时,配置文件的存在使得配置信息更易于共享、重用和管理,提高了代码的可维护性和灵活性。

总结起来,Java项目配置文件的产生是为了优化配置管理、提高代码可维护性和灵活性,在实际开发中起着非常重要的作用。

2.2 项目使用配置文件好处

通过上面的介绍以及开发中总结的经验,可以说java项目引入配置文件之后优势是很明显的,具体来说包括:

  • 灵活性

    • 配置文件使得应用程序的配置信息与代码分离,可以根据需要随时修改配置而不必重新编译代码。这种灵活性使得应用程序更易于维护和扩展。
  • 安全性

    • 敏感信息(如数据库连接信息、密码等)通常不应硬编码在代码中,通过配置文件可以将这些敏感信息单独存放,加密或者做一些安全处理,避免泄露。
  • 可重用性

    • 配置文件可以被多个模块或组件共享使用,避免了重复配置的问题。同时,配置文件的内容可以在不同项目中重复利用,提高开发效率。
  • 易于管理

    • 将配置信息集中到配置文件中,便于统一管理和查看应用程序的各项配置参数,方便开发人员对配置进行修改和调整。
  • 环境适配

    • 通过配置文件可以为不同的环境(开发、测试、生产)配置不同的参数,应用程序能够方便的适配不同的部署环境。

使用配置文件能够提高Java应用程序的可维护性、灵活性和安全性,是一种良好的开发实践。

2.3 springboot项目配置文件的必要性

当前,在我们讨论微服务开发时,很容易想到底层框架使用springboot,springboot的使用让微服务的开发变得更简单,因此围绕着springboot开发来说,项目涉及到的配置文件越来越多,也越来越复杂时,使用配置文件就显得非常必要了,具体来说,Spring Boot项目配置文件的必要性在于它为开发人员提供了一种灵活且方便的方式来管理应用程序的配置信息。以下是几个主要原因:

  • 外部化配置

    • 使用配置文件,可以将应用程序的配置参数从代码中分离出来,使配置更易于修改和维护。通过配置文件,开发人员可以根据不同环境(开发、测试、生产)或需求来定制不同的配置,而无需修改代码。
  • 注入配置信息

    • Spring Boot框架支持将配置文件中的配置信息注入到应用程序中,开发人员可以通过注解或属性文件的方式轻松地获取配置参数,并在应用程序中使用这些参数。
  • 自动装配

    • Spring Boot会自动加载并解析应用程序的配置文件,根据配置信息来完成各种组件的初始化和装配工作。这样可以简化开发流程,减少手动配置的工作量。
  • 多环境支持

    • Spring Boot允许开发人员为不同的环境(如开发、测试、生产)创建不同的配置文件,使得应用程序在不同环境下能够正确加载相应的配置信息。

总之,Spring Boot项目配置文件的存在使得配置信息可灵活管理,并且与代码分离,有助于提高代码的可维护性、扩展性和可读性。因此,配置文件在Spring Boot项目中是非常必要的。

2.4 微服务架构下配置文件使用场景

在微服务开发中,配置文件可以说是必不可少的,不管是服务工程本身的配置文件,还是使用外部的配置文件,比如读取来自配置中心的配置信息,都是对现有的架构设计中很好的补充,具体来说,微服务架构中配置文件的使用场景主要有以下几个方面:

  • 服务发现与注册

    • 微服务架构中的服务通常会通过服务发现机制来注册和发现其他服务。配置文件可以包含服务的注册信息(如地址、端口等),帮助服务实例在运行时正确注册到服务注册中心,并能够让其他服务发现并调用该服务。
  • 动态配置管理

    • 微服务架构下,服务的配置可能需要频繁变更,例如数据库连接信息、日志级别、缓存设置等。通过配置文件,可以实现动态配置管理,使得服务在运行时可以根据配置文件的变化自动加载最新的配置参数,而不需要重启服务。
  • 环境切换

    • 微服务通常会部署在多个环境(如开发、测试、生产)中。通过配置文件可以区分不同环境下的配置参数,使得服务能够根据当前所处环境加载相应的配置信息,从而保证服务在不同环境下正常运行。
  • 敏感信息管理

    • 微服务架构中,一些敏感的配置信息(如密码、密钥等)往往不适宜明文写在代码中。通过配置文件可以对这些敏感信息进行加密处理,提高系统的安全性。
  • 版本控制

    • 将配置信息存放在配置文件中,有利于进行版本控制。开发团队可以轻松地跟踪配置文件的变化历史,并进行回滚或比较不同版本的配置信息。

总的来说,微服务架构中配置文件的使用场景涵盖了服务注册、动态配置管理、环境切换、敏感信息管理以及版本控制等方面,是微服务开发中不可或缺的重要组成部分。

三、java读取配置文件常用方法

在java中,可以通过多种方式读取外部的配置文件,下面提供几种常用的方式。工程目录结构如下:

3.1 使用Properties类读取配置文件

3.1.1 使用getResourceAsStream读取

在resources目录下提供一个config.properties的配置文件,配置内容如下:

bash 复制代码
server.name=testApp
server.port=8088

默认情况下,maven工程中可以读取到resources目录下的文件,而不用加resources作为绝对路径,参考如下示例:

java 复制代码
    @Test
    public void test1() throws IOException {
        InputStream inputStream = this.getClass().getResourceAsStream("/config.properties");
        Properties properties = new Properties();
        properties.load(inputStream);
        properties.list(System.out);
        System.out.println("==============================================");
        String serverName = properties.getProperty("server.name");
        String serverPort = properties.getProperty("server.port");
        System.out.println("serverName = " + serverName);
        System.out.println("serverPort = " + serverPort);
    }

但是如果是在resources目录下自定义的其他目录下,像下面这样

此时,如果使用Properties读取里面的配置文件,可以想下面这样;

java 复制代码
    @Test
    public void readRedisProperties() throws IOException {
        InputStream inputStream = this.getClass().getResourceAsStream("/config/redis.properties");
        Properties properties=new Properties();
        properties.load(inputStream);
        System.out.println("redis.host="+properties.getProperty("redis.host"));
        System.out.println("redis.port="+properties.getProperty("redis.port"));
    }

3.1.2 使用getClassLoader读取

如果使用getClassLoader的方式读取配置文件,此时则修改为下面的写法

java 复制代码
    /**
     * 读取config.properties
     * @throws IOException
     */
    @Test
    public void readProperties2() throws IOException {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties");
        Properties properties=new Properties();
        properties.load(inputStream);
        String serverName = properties.getProperty("server.name");
        String serverPort = properties.getProperty("server.port");
        System.out.println("serverName = " + serverName);
        System.out.println("serverPort = " + serverPort);
    }

    /**
     * 读取config/redis.properties
     * @throws IOException
     */
    @Test
    public void readRedisPropertiesV2() throws IOException {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config/redis.properties");
        Properties properties=new Properties();
        properties.load(inputStream);
        System.out.println("redis.host="+properties.getProperty("redis.host"));
        System.out.println("redis.port="+properties.getProperty("redis.port"));
    }	

上面通过两种方式都可以读取到配置文件内容的信息,但是两者还是有区别的,具体来说:

  • Class.getResourceAsStream(),是 从当前类所在的位置开始查找配置文件位置;

    • 要找到config.properties和redis.properties必须加/从classpath下开始查找;
  • Class.getClassLoader().getResourceAsStream() ;

    • 默认就从classpath路径下开始查找,加上/会报空指针;

3.2 使用ClassLoader读取配置文件

也可以使用ClassLoader来进行读取和加载配置文件到Properties中

java 复制代码
    @Test
    public void readRedisPropertiesV3() throws IOException {
        InputStream inputStream = ClassLoader.getSystemResourceAsStream("config.properties");
        Properties properties=new Properties();
        properties.load(inputStream);
        System.out.println("server.name="+properties.getProperty("server.name"));
        System.out.println("server.port="+properties.getProperty("server.port"));
    }

四、spring中读取配置文件常用方法

在spring或springboot中,除了上述java默认提供的配置文件读取的方法外,还有其他的方式,下面介绍一些常用的读取方法。

4.1 使用ClassPathResource读取

在使用spring进行开发中,可以利用ClassPathResource这个类进行加载读取

java 复制代码
    @Test
    public void readProperties4() throws IOException {
        ClassPathResource resource = new ClassPathResource("config.properties");
        Properties properties= PropertiesLoaderUtils.loadProperties(resource);
        System.out.println("server.name="+properties.getProperty("server.name"));
        System.out.println("server.port="+properties.getProperty("server.port"));
    }

4.2 使用PropertyResourceBundle读取

ResourceBundle没有继承什么类,是一个单个的抽象类,该类可以说是国际化版的Properties,简单说就是可以根据本地化或语言的不同读取不同的配置文件。

java 复制代码
    @Test
    public void readProperties5() throws IOException {
        InputStream inputStream = ClassLoader.getSystemResourceAsStream("config.properties");
        PropertyResourceBundle bundle = new PropertyResourceBundle(inputStream);
        System.out.println(bundle.getString("server.name"));
        System.out.println(bundle.getString("server.port"));
    }

也可以不用输入后缀,像下面这样,之所以可以这样写,与ResourceBundle自身的配置文件读取机制有关。

java 复制代码
    @Test
    public void readProperties6()  {
        ResourceBundle bundle=ResourceBundle.getBundle("config/redis");
        System.out.println(bundle.getString("redis.host"));
        System.out.println(bundle.getString("redis.port"));
    }

4.3 使用PropertiesLoaderUtils 读取

Spring 提供的 PropertiesLoaderUtils 允许您直接通过基于类路径的文件地址加载属性资源。这种方式最大的好处就是:实时加载配置文件,修改后立即生效,不必重启。参考下面的示例:

java 复制代码
    @Test
    public void springUtilTest() throws Exception {
        Properties props = PropertiesLoaderUtils.loadAllProperties("config.properties");
        for (Object key : props.keySet()) {
            System.out.print(key + ":");
            System.out.println(props.get(key));
        }
    }

4.4 使用FileSystemResource读取

在spring项目中,加载项目外的配置文件时,可以考虑使用FileSystemResource进行读取,比如加载配置文件中的信息为容器管理的bean时;

java 复制代码
    @Test
    public void testFileSystemResource() {
        Resource resource = new FileSystemResource("D:\applicationContext.xml");
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);
    }

类似的,针对不同类型的配置文件,spring还提供了很多种写法,如下。

4.4.1 使用FileSystemXmlApplicationContext读取

解析并获取配置文件中定义bean的数量

java 复制代码
    @Test
    public void test05() {
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("C:/applicationContext.xml");
         定义bean的总数
        System.out.println(context.getBeanDefinitionCount());
    }

4.4.2 使用ClassPathXmlApplicationContext读取

解析并获取配置文件中定义的指定的bean信息

java 复制代码
@Test
public void test06() {
        String[] filepath = {"applicationContext.xml"};
        ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext(filepath);
        UserService studentService = (UserService) factory.getBean("userService");
    }

五、springboot读取配置文件常用方法

springboot基于spring的基础上,做了更多功能上的扩展升级,在配置文件读取和使用方面,也做了更丰富的补充,从而完成更复杂的对于配置文件读取和加载使用的功能,Spring Boot 中读取配置文件有以下 5 种方法:

  • 使用 @Value 读取配置文件。

  • 使用 @ConfigurationProperties 读取配置文件。

  • 使用 Environment 读取配置文件。

  • 使用 @PropertySource 读取配置文件。

  • 使用原生方式读取配置文件。

如下,在springboot工程中有一个application.yml配置文件,这也是springboot项目中经常使用的最重要的配置文件之一,有如下几行配置内容:

java 复制代码
server:
  port: 8088

user:
  pro:
    name: jerry
    age: 28
    city: beijing

下面通过不同的方式读取上述的配置信息。首先,需要为工程引入springboot的单元测试类

java 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

5.1 使用@Value注解读取

@Value注解是Spring Framework中的一个注解,它可以用来将外部配置文件中的值注入到Spring Bean中。通过在字段或setter方法上使用@Value注解,我们可以直接从属性文件、环境变量或其他地方读取配置值,并注入到Spring Bean中。

5.1.1 读取单个属性值

从配置文件中读取某个属性值,如下代码所示:

java 复制代码
@SpringBootTest(classes = BootApp.class)
@RunWith(SpringRunner.class)
public class ConfigTest {

    @Value("${user.pro.name}")
    private String name;

    @Test
    public void readConfigTest1(){
        System.out.println("user.pro.name == " + name);
    }

}

如果是放在一个类中,像下面这样,则表示,@Value("${my.property}")会从配置文件(如application.properties或application.yml)中读取名为my.property的属性值,并注入到myProperty字段中。

java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    
    @Value("${my.property}")
    private String myProperty;
}

5.1.2 使用默认值

像下面这样,如果从配置文件中读取不到user.pro.work的属性值,则会使用默认值manager

java 复制代码
    @Value("${user.pro.work:manager}")
    private String name;

    @Test
    public void readConfigTest1(){
        System.out.println("user.pro.name == " + name);
    }

5.1.3 支持spel表达式

可以使用SpEL表达式来动态计算属性值。在下面这个例子中,javaHome属性的值将会是Java安装目录的路径。

java 复制代码
    @Value("#{systemProperties['java.home']}")
    private String javaHome;

    @Test
    public void readConfigTest1(){
        System.out.println("user.pro.name == " + name);
        System.out.println("systemProperties == " + javaHome);
    }

5.2 @ConfigurationProperties 读取配置文件

@ConfigurationProperties 和 @Value 的使用略微不同,@Value 是读取单个配置项的,而 @ConfigurationProperties 是读取一组配置项的,我们可以使用 @ConfigurationProperties 加实体类读取一组配置项:

java 复制代码
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@ConfigurationProperties(prefix = "user.pro")
@Configuration
public class UserProperties {

    private String name;
    private String city;
    private Integer age;

}

其中 ,prefix 表示读取一组配置项的根 name,相当于 Java 中的类名,最后再把此配置类,注入到某一个类中就可以使用了,如下代码所示:

java 复制代码
    @Autowired
    private UserProperties userProperties;

    @Test
    public void readUserProperties(){
        System.out.println("userName :" + userProperties.getName());
        System.out.println("userAge == " + userProperties.getAge());
        System.out.println("userCity == " + userProperties.getCity());
    }

5.2.1 @ConfigurationProperties 读取配置文件原理

@ConfigurationProperties注解是Spring Boot中一个用于绑定配置属性的注解,通过它可以将配置文件中的属性值自动绑定到Java对象的属性上。这样可以方便地将配置文件中的属性与Java对象关联起来,实现配置信息的读取和管理。该注解实现原理如下:

  • 定义@ConfigurationProperties注解:

    • 在Java类中使用@ConfigurationProperties注解来标识需要绑定配置属性的类或属性。
  • 加载配置文件:

    • Spring Boot会加载classpath下的application.properties或application.yml等配置文件,并将这些配置文件中的属性值存储在Environment中。
  • 自动绑定配置属性:

    • 当@ConfigurationProperties注解和Java类结合使用时,Spring Boot会自动将配置文件中的属性值与Java对象的对应属性进行绑定。要求Java对象的属性名与配置文件中的属性名一致,支持驼峰命名和短横线分隔命名的映射。
  • 属性值注入:

    • 通过@ConfigurationProperties注解,可以直接将配置文件中的属性值注入到Java对象的属性中,从而实现配置信息的读取和管理。

5.2.2 @ConfigurationPropertiess补充点1

在实际使用中,有下面一点容易忽略,即在配置文件中,如果配置信息以英文-结尾,在配置类中,属性定义时可以写成驼峰形式,如下配置文件中增加一个属性:

java 复制代码
user:
  pro:
    name: jerry
    age: 28
    city: beijing
    current-address: shanghai

在类中则可以像下面这样编写

java 复制代码
@Data
@ConfigurationProperties(prefix = "user.pro")
@Configuration
public class UserProperties {

    private String name;
    private String city;
    private Integer age;
    private String currentAddress;
}

5.2.2 @ConfigurationProperties补充点2

@ConfigurationProperties注解既可以在类上使用,也可以使用在@Bean注解上面,如下,我们定义一个bean,然后使用该注解将配置参数引用,使用步骤如下:

新增如下配置信息

java 复制代码
app:
  config:
    app-name: user-app
    app-url: 192.168.1.332
    remote-validate: true

定义一个类,类中的属性与配置文件中的属性保持一致

java 复制代码
@Data
public class AppConfigProperties {
    private String appName;
    private String appUrl;
    private boolean remoteValidate;
}

定义一个配置类,再在标注为@Bean的方法上使用@ConfigurationProperties注解

java 复制代码
@Component
public class AppConfig {

    @Bean
    @ConfigurationProperties(prefix = "app.config")
    public AppConfigProperties appConfigProperties(){
        return new AppConfigProperties();
    }
}

最后在需要的地方注入该AppConfigProperties类,由于被作为bean纳入到spring容器中了,在下面的接口中就可以直接使用;

java 复制代码
@RestController
public class AppController {

    @Autowired
    private AppConfigProperties appConfigProperties;

    //localhost:8088/getAppConfig
    @GetMapping("/getAppConfig")
    public String getAppConfig(){
        String appName = appConfigProperties.getAppName();
        String appUrl = appConfigProperties.getAppUrl();
        return appName +  " - " +appUrl;
    }
}

5.2.3 @ConfigurationProperties补充点3

在有些第三方组件的源码或spring源码中,还能看到配置类中的bean互相引用的情况,比如下面这样:

java 复制代码
@Component
public class AppConfig {

    @Bean
    @ConfigurationProperties(prefix = "app.config")
    public AppConfigProperties appConfigProperties(){
        return new AppConfigProperties();
    }

    @Bean
    public UploadComponent uploadComponent(@Qualifier("appConfigProperties") AppConfigProperties appConfigProperties){
        UploadComponent uploadComponent = new UploadComponent();
        uploadComponent.setAppConfigProperties(appConfigProperties);
        return uploadComponent;
    }

}

在当前的配置类中,除了AppConfigProperties会被实例化为一个bean,同时需要实例化的bean还有UploadComponent这个类,该类代码如下:

java 复制代码
@Data
public class UploadComponent {

    private AppConfigProperties appConfigProperties;

    public void upload(){
        System.out.println("upload url :" + appConfigProperties.getAppUrl());
    }
}

UploadComponent作为Bean的实例化过程如下:

  • 容器示例化名为uploadComponent的bean;

  • uploadComponent实例化过程中检测到还有参数AppConfigProperties,于是检测容器中是否有AppConfigProperties实例化对象,然后作为方法参数注入进来;

    • 如果方法参数之前使用了@Qualifier,则注解中的值与上述已完成的AppConfigProperties实例bean名称一致即可;
  • uploadComponent将AppConfigProperties实例拿过来使用,设置为类的属性,最后作为spring的bean完成实例化;

5.2.4 @ConfigurationProperties补充点4

在配置文件中,如果想要将配置信息以集合的形式读取出来该怎么办呢?比如下面这样,相同的配置信息有多行:

java 复制代码
spring:
  test:
    orders:
      - order-id: 001
        order-name: 批次订单1
        addr: 杭州
      - order-id: 002
        order-name: 批次订单2
        addr: 武汉

首先,仍然定义一个类

java 复制代码
@Data
public class OrderProperties {

    private String orderId;
    private String orderName;
    private String addr;
}

定义一个配置类,属性为OrderProperties的集合,属性值为orders

java 复制代码
@Configuration
@ConfigurationProperties(prefix = "spring.test")
@Data
public class OrderConfig {

    private List<OrderProperties> orders;

}

然后再在使用的地方注入OrderConfig即可

java 复制代码
    @Autowired
    private OrderConfig orderConfig;

    //localhost:8088/getOrderConfig
    @GetMapping("/getOrderConfig")
    public List<OrderProperties> getOrderConfig(){
        List<OrderProperties> orderProperties = orderConfig.getOrders();
        return orderProperties;
    }

5.3 使用 @PropertySource 读取配置文件

使用 @PropertySource 注解可以用来指定读取某个配置文件,比如指定读取 application.properties 配置文件的配置内容,如下,仍然以读取resources目录下的config配置文件为例进行说明,首先在启动类中使用@PropertySource 注解引入该配置

java 复制代码
@SpringBootApplication
@PropertySource("classpath:config.properties")
public class BootApp {

    public static void main(String[] args) {
        SpringApplication.run(BootApp.class,args);
    }

}

再在需要的地方使用@Value注入即可使用,比如在下面的测试接口中即可使用

java 复制代码
@RestController
public class TestController {

    @Value("${server.name}")
    private String serverName;

    //localhost:8088/get
    @GetMapping("/get")
    public String getProperties(){
        System.out.println(serverName);
        return serverName;
    }

}

如果出现了中文乱码,可以使用下面指定编码的方式处理

java 复制代码
@PropertySource(value = "config.properties", encoding = "utf-8")

5.3.1 @PropertySource 读取配置文件原理

在Spring框架中,@PropertySource注解用于指定外部属性文件的位置,并将其加载到Spring的Environment中,以供应用程序使用。@PropertySource注解通常与@Value注解一起使用,用于读取配置文件中的属性值。该注解的使用原理如下:

  • 注解定义:

    • 开发者在Spring配置类中使用@PropertySource注解来指定外部属性文件的位置,可指定一个或多个属性文件路径,Spring会自动加载这些文件;
  • 加载属性文件:

    • 当Spring容器启动时,会扫描带有@PropertySource注解的配置类,并加载指定的属性文件。这些属性文件通常包含键值对形式的配置信息,比如key=value;
  • 属性文件解析:

    • Spring框架会解析属性文件中的配置信息,并将其存储到Environment对象中。这样,应用程序就可以通过Environment对象来获取配置属性的值了;
  • 使用@Value注解注入:

    • 开发者可以使用@Value注解来注入属性文件中的属性值。通过@Value("${key}")的方式,可以直接从Environment中获取对应键的值,从而在代码中使用配置属性。

总结来说,@PropertySource注解作用是指定外部属性文件的位置,并将其加载到Spring的Environment中,方便应用程序读取和使用配置信息。结合@Value注解,就可以方便的在Spring应用程序中使用外部配置文件中的属性值。

5.4 使用Environment 读取配置文件

在Spring Boot中,可以使用Environment对象来读取配置文件中的属性。Environment是Spring框架中用于表示当前运行环境的接口,可以通过它来获取应用程序的配置信息。Environment的主要作用是提供统一的访问方式来获取应用程序的配置信息,包括系统属性、环境变量、命令行参数以及配置文件中的属性。它将这些配置信息统一管理,并提供了各种方法来获取和操作这些配置属性。

java 复制代码
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 org.springframework.core.env.Environment;

@RestController
public class TestController {

    @Autowired
    private Environment environment;

    //localhost:8088/getEnvironment
    @GetMapping("/getEnvironment")
    public String getEnvironment(){
        String serverPort = environment.getProperty("server.port");
        System.out.println(environment.getProperty("server.port"));
        return serverPort;
    }
}

5.4.1 Environment读取配置文件原理

在Spring Framework中,Environment接口代表了应用程序运行时环境,可以用于读取配置属性,在Spring Boot中,Environment的实现类是StandardEnvironment。其读取配置文件的原理如下:

  • 加载配置文件:

    • Spring Boot会自动加载classpath下的application.properties或application.yml等配置文件,这些配置文件中定义的属性会被解析并保存到Environment中。
  • 解析配置属性:

    • 通过Environment的getProperty()方法可以获取指定属性的值,该方法会首先从系统属性、环境变量、命令行参数等位置查找属性值,然后再依次从配置文件中查找。
  • 使用@Value注解:

    • 除了通过getProperty()方法获取属性值外,还可以使用@Value注解来注入属性值。@Value注解可以直接从Environment中获取配置属性的值,简化了代码编写。

5.5 使用原生方式读取配置文件

还可以使用最原始的方式 Properties 对象来读取配置文件,如下代码所示

java 复制代码
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

@Configuration
public class PropertiesConfig implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        Properties props = new Properties();
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(
                    this.getClass().getClassLoader().getResourceAsStream("config.properties"),
                    StandardCharsets.UTF_8);
            props.load(inputStreamReader);
            System.out.println(props.getProperty("server.name"));
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

六、springboot读取外部配置文件

如今,微服务开发在技术选型中通常会直接集成第三方框架,比如使用springcloud、dubbo等作为微服务框架进行开发,基于框架之下,通常都会使用统一的外部配置中心作为配置文件集中管理的地方,因此在读取配置文件时,会稍有区别,下面以springboot中读取nacos配置中心文件为例进行说明。

6.1 操作过程

6.1.1 搭建nacos服务

搭建nacos服务,这里我使用docker快速搭建了一个nacos2.X版本的服务

6.1.2 增加两个配置文件

在控制台界面上,增加如下两个配置文件,关于nacos配置文件的命名规则,可以参考这篇文章,nacos使用详解

nacos-config-client-dev.yml配置内容如下:

common.yml配置内容如下,common配置文件将会作为多个微服务项目的共享配置文件使用

6.1.3 引入pom依赖

需要注意的是,导入nacos依赖时,springcloud-alibaba版本与springboot版本的匹配

java 复制代码
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <log4j.version>1.2.17</log4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--nacos-config 配置中心-自带动态刷新-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--nacos-discovery 注册中心-服务发现与注册-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

6.1.4 添加配置文件

使用nacos作为配置文件中心时,在springboot工程中定义配置文件时,需要引入bootstrap.yaml配置文件,通过该文件优先加载nacos的配置文件。

bootstrap.yaml配置文件内容

java 复制代码
server:
  port: 8087

spring:
  profiles:
    active: dev
  application:
    #这里的名称和nacos中的配置文件名称保持一致
    name: nacos-config-client

  cloud:
    nacos:
      discovery:
        server-addr: IP:8848
      config:
        server-addr: IP:8848
        #指定要加载的配置文件的格式后缀名
        file-extension: yml
        group: DEFAULT_GROUP
        ext-config:
          - data-id: common.yml
            group: DEFAULT_GROUP
            refresh: true

application.yaml配置文件中,可以定义一些常规的配置信息即可。

6.1.4 增加测试接口读取配置

通过代码不难看出,在配置的使用上,也是通过@Value注解,将需要使用的配置内容注入即可

java 复制代码
@RestController
@RefreshScope
public class NacosController {

    @Value("${config.info.name}")
    private String configName;

    @Value("${app.center.key}")
    private String appCenterKey;

    //localhost:8087/get/config
    @GetMapping("/get/config")
    public String getConfigName(){
        return configName;
    }

    //localhost:8087/get/key
    @GetMapping("/get/key")
    public String getCommonConfig(){
        return appCenterKey;
    }

}

七、写在文末

本文通过较大的篇幅详细分享了java中读取配置文件的各种方式,从spring到springboot中各种读取配置文件的方式通过案例进行了详细的说明,可以说,对配置文件的使用和维护是日常开发中的一项重要内容,使用得当,可以给开发带来相当的便利,有必要全面深入的掌握,本篇到此结束,感谢观看。