一、springboot中读取配置文件的方式

在一个springboot应用中,读取配置文件时通常可以采用两种方式,@valueConfigurationProperties

1.1 使用value注解

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

在一使用个spring bean中使用@value直接指定要读取的配置项即可直接读取

1.2 使用ConfigurationProperties注解

首选需要创建一个属性类,并加上这个注解,指定要读取的配置文件前缀


@ConfigurationProperties(prefix = "user")
//@Component
public class UserProperties {
    private String username;
    private String age;
    private Address address;//具有层级关系的属性可以嵌套

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getAge() {
        return this.age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

然后把这个类加入到spring容器中,在需要用到配置文件属性的地方直接注入这个类。

注意把这个类加入到容器中,可以给这个类上加@Component注解,也可以在配置类上使用

@EnableConfigurationProperties 来加入

@SpringBootApplication
@EnableConfigurationProperties(value = {UserProperties.class})
public class ConfigFileApp {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigFileApp.class);
        MyService myService = applicationContext.getBean(MyService.class);
        myService.sayHello();

    }
}

要使用的地方直接注入


@Component
public class MyService {

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

    @Autowired
    private UserProperties userProperties;

    public void sayHello() {
        System.out.println("user.name"+name);
        System.out.println("user.age"+age);

        System.out.println("获取方式2 name:"+userProperties.getUsername());
        System.out.println("获取方式2: age"+userProperties.getAge());

        System.out.println("province:"+userProperties.getAddress().getProvince());
        System.out.println("city:"+userProperties.getAddress().getCity());
    }
}

user:
  username: tom
  age: 18
  address:
    province: 陕西
    city: 西安

二、配置文件区分环境

配置文件区分环境有两种方式

2.1 准备多个不同后缀名的文件

准备两个文件,application-dev.yml和application-prd.yml,不同文件中写对应环境的配置。

2.2 同一个文件中

在同一个文件中,可以用三个短横线隔开不同环境的配置文件,用spring.profiles来命名配置文件的环境

spring:
  profiles: dev
service-name: dev-service

---
spring:
  profiles: prd
service-name: prd-service

2.3 如何指定生效的配置文件

方式1:使用spring.profiles.active指定

在配置文件的最上方公共配置部分(不区分环境的部分)使用 这个key来指定生效的配置,

这时完整的配置文件如下

# 这一部分是公共配置,不区分环境
spring:
  profiles:
    active: dev
# 下边这两部分是区分环境的配置
---
spring:
  profiles: dev
service-name: dev-service

---
spring:
  profiles: prd
service-name: prd-service

方式2:使用启动参数

(1)使用vm的启动参数,-Dspring.profiles.active=dev

(2)使用环境变量参数,spring.profiles.active=dev

注意在springboot中vm参数的优先级>环境变量参数>yml中指定的active,环境变量参数实际读取的是系统的环境变量,idea中为方便开发提供了环境变量参数可以直接指定不用修改系统环境变量。

三、读取配置文件的原理

本文使用的springboot版本是2.1.3.RELEASE,不同版本中配置文件读取后封装成的对象可能不一样,但原理是一样的。

spring提供了一个ConfigurableEnvironment 接口来对配置进行抽象,在这个版本的springboot中使用的实现类

StandardEnvironment,先简单看一下用法

public class MyTest2 {
    public static void main(String[] args) {
        //springboot中配置文件解析后会封装成这个对象,这个对象中可以读取到vm参数,环境变量参数,和配置文件中的内容
        StandardEnvironment environment = new StandardEnvironment();
        //读环境变量参数
        String java_home = environment.getProperty("JAVA_HOME");
        System.out.println(java_home);
        //读vm参数
        String active = environment.getProperty("spring.profiles.active");
        System.out.println(active);
    }
}

上边演示了StandardEnvironment对象的基本用法,下边看下如何读取yml中的配置


public class MyTest2 {
    public static void main(String[] args) throws IOException {
        //springboot中配置文件解析后会封装成这个对象,这个对象中可以读取到vm参数,环境变量参数,和配置文件中的内容
        StandardEnvironment environment = new StandardEnvironment();
        //读环境变量参数
        String java_home = environment.getProperty("JAVA_HOME");
        System.out.println(java_home);
        //读vm参数
        String active = environment.getProperty("spring.profiles.active");
        System.out.println(active);

        //读取yml配置
        YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader();
        //第一个参数只是一个标识,没有意义
        List<PropertySource<?>> propertySources = yamlPropertySourceLoader.load("aa", new ClassPathResource("application.yml"));
        //把读取到的propertySources添加到StandardEnvironment中
        for (PropertySource<?> propertySource : propertySources) {
            environment.getPropertySources().addLast(propertySource);
        }

        //尝试读取配置文件中的key
        String username = environment.getProperty("user.username");
        System.out.println(username);
    }
}

可以看到要使用YamlPropertySourceLoader 来解析yaml文件。

springboot在启动过程中也做了类似的事情,入口是在启动过程中会发布一个ApplicationEnvironmentPreparedEvent 事件,然后这个事件会被ConfigFileApplicationListener 监听到,在它的onApplicationEvent方法中会加载一些EnvironmentPostProcessor,配置文件的解析就是通过具体的

EnvironmentPostProcessor 实现的。