欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2、Spring Boot中属性的获取

程序员文章站 2022-07-10 18:12:41
...

在本节我们来讨论下如何获取配置文件里面的属性

1、属性的获取

Spring Boot要从application.yml(application.properties)中获取变量的值,比如application.properties中有下面的属性:

huahua=lili

那么要获得这个属性,有以下几种方式

1.1、通过context获取

@SpringBootApplication
public class SpringBootConfigApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext application = 
            SpringApplication.run(
                SpringBootConfigApplication.class, args);
        System.out.println(application.getEnvironment()
            .getProperty("huahua"));
        application.close();
    }
}

1.2、通过注入Environment对象获取

@Component
public class UserConfig {
    @Autowired
    private Environment env;

    public void show(){
        System.out.println("name = " + env.getProperty("huahua"));
    }
}

@SpringBootApplication
public class SpringBootConfigApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext application = 
                SpringApplication.run(
                SpringBootConfigApplication.class, args);
        application.getBean(UserConfig.class).show();
        application.close();
    }
}

通过env.getProperty()方法可以获取一个整数,比如huahua属性是一个整数。那么可以通过evn的重载方法getProperty(String prop, Class clazz)获取。

System.out.println(env.getProperty("huahua", Integer.class));

来获取,同样也可以获取boolean类型的值

1.3、通过@Value()注解

@Component
public class UserConfig {

    @Value("${huahua}")
    private String huahua;

    public void show(){
        System.out.println("name = " + huahua);
    }
}

SpringBootConfigApplication类保持不变。然后运行它,仍然可以达到统一的效果。

需要注意的是如果通过@Value注解的形式注解一个没有的属性,那么是会启动报错的,而通过Environment对象获取一个没有的属性,会返回null。

1.4、属性的默认值

比如我们的classpath下没有host的这个属性,那么我们运行下面的代码

@SpringBootApplication
public class SpringBootConfigApplication {

    @Value("${host:com.dragon}")
    private String host;

    public static void main(String[] args) {
        ConfigurableApplicationContext application = 
            SpringApplication.run(
            SpringBootConfigApplication.class, args);
        System.out.println(application.getEnvironment()
            .getProperty("host"));
        System.out.println(application.getBean(
            SpringBootConfigApplication.class).host);
        application.close();
    }
}

将会有如下的打印
2、Spring Boot中属性的获取

在上面的示例中,我们将@Value注解了一个默认值。同样Environment对象也是可以有默认值的。看下面的代码

@SpringBootApplication
public class SpringBootConfigApplication {
    @Value("${host:com.dragon}")
    private String host;
    public static void main(String[] args) {
        ConfigurableApplicationContext application = SpringApplication.run(SpringBootConfigApplication.class, args);
        System.out.println(application.getEnvironment().getProperty("host","dragon.com.cn"));
        System.out.println(application.getBean(SpringBootConfigApplication.class).host);
        application.close();
    }
}

2、Spring Boot中属性的获取

除了上面的2种设置默认值,我们还有下面的方式可以设置默认值

SpringApplication application = new SpringApplication(SpringBootConfigApplication.class);
Map<String, Object> defaultProperties = new HashMap<>();
defaultProperties.put("host", "192.168.1.100");
application.setDefaultProperties(defaultProperties);

然后我们来看启动类

@SpringBootApplication
public class SpringBootConfigApplication {

    @Value("${host:com.dragon}")
    private String host;

    public static void main(String[] args) {    
        SpringApplication application = new SpringApplication(SpringBootConfigApplication.class);
        Map<String, Object> defaultProperties = new HashMap<>();
            defaultProperties.put("host", "192.168.1.100");
            application.setDefaultProperties(defaultProperties);

            ConfigurableApplicationContext context = application.run(args);
        System.out.println(context.getEnvironment().getProperty("host","dragon.com.cn"));
        System.out.println(context.getBean(SpringBootConfigApplication.class).host);    
        context.close();
    }
}

运行该类,其打印如下
2、Spring Boot中属性的获取
也就是说通过application.setDefaultProperties()设置的方式,优先级最高:
获取属性,但是指定默认值,有3种方式:

a、@Value("${host:com.dragon}")
b、context.getEnvironment().getProperty("host","dragon.com.cn")
c、
SpringApplication application = new SpringApplication(SpringBootConfigApplication.class);
Map<String, Object> defaultProperties = new HashMap<>();
defaultProperties.put("host", "192.168.1.100");
application.setDefaultProperties(defaultProperties);

1.5、配置文件里面获取配置项

配置文件里面除了配置普通的外,还可以使用当前配置的文件。如application.yml有如下配置:

propera: a
properb: 20
content: "propera: ${propera}, properb: ${properb}"

那么content的值就是 propera: a, properb: 20

2、配置文件及其文件路径

Spring Boot默认的配置文件是application.yml(application.properties),
默认的位置是有4个:classpath根目录、classpath:/config、file:/、file:config/。
如果我们的配置文件不叫application.properties,而是叫app.properties,那么很显然这种情况默认是无法启动的。比如说我们的目录结构如下
2、Spring Boot中属性的获取
在我们打成jar包后(这里需要注意的是,默认maven的打包是要执行test里面的逻辑,我们上面的代码里面的src/test/java中是有代码的,所以打包的命令要是clean compile package -Dmaven.test.skip=true),通过spring.config.name可以来指定启动的配置文件:

java -jar spring-boot-config-0.0.1-SNAPSHOT.jar --spring.config.name=app

也可以运行打包完成后的jar。这种情况就是app.properties在classpath目录下。可以只指定配置文件的名称从而忽略后缀。

但是也还有一种情况就是指定外部的配置文件,比如配置文件在某个目录下,那么这时候需要使用spring.config.location来指定:

java -jar spring-boot-config-0.0.1-SNAPSHOT.jar --spring.config.location=file:/Users/aa/Downloads/app.properties 

需要注意的是,通过spring.config.location是需要指定配置文件的绝对路径(包含后缀)。同时,也可以指定多个配置文件,多个配置文件用逗号分隔,如:

java -jar spring-boot-config-0.0.1-SNAPSHOT.jar --spring.config.location=file:/Users/aa/Downloads/app.properties,file:/Users/aa/Downloads/app2.properties 
这里需要注意一点:逗号之间不能有空格。

通过上面的讲解,我们知道文件的指定方式有两种:1、classpath. 2、file:/ 。第一种是classpath,第二种是文件系统加载。

2.1、其他的配置文件

除了上面的spring boot需要的配置文件,我们可能还有其他的配置文件,比如jdbc.properties,那么这个时候可以通过下面的方式读取:

@Configuration
@PropertySource(value = "classpath:config/jdbc.properties")
public class JdbcConfig {
    @Value("$spring.datasource.driverClassName}")
    private String driverClassName;

    public void show(){
        System.out.println("driverClassName : " + driverClassName);
    }
}

@PropertySource可以指定多个配置文件。如

@PropertySource(value = {"classpath:config/jdbc.properties", "classpath:config/redis.properties"})

2.2、带有前缀规律的配置文件

比如我们有个book.properties的配置文件,其内容如下:

book.name=spring boot
book.price=1

那么可以通过如下的配置来获取对应的属性

@Configuration
@PropertySource(value = "classpath:config/book.properties")
@ConfigurationProperties(prefix = "book")
public class BookConfig {
    private String name;
    private String price;
    // 省略 getter/setter
}

2.3、其他类型的注入

spring boot除了上面的简单注入属性外,还有其他注入属性。

2.3.1、注入List数据

ds.hosts[0] = 192.168.1.100
ds.hosts[1] = 192.168.1.101
ds.hosts[2] = 192.168.1.102
ds.hosts[3] = 192.168.1.103

上面的方式配置在application.properties(或者能够读取到的其他配置文件)中,然后通过

        private List<String> hosts ;

就可以注入就去

2.3.2、注入数组

数组在配置文件中的写法和List一致:

ds.ports[0] = 8000
ds.ports[1] = 8001
ds.ports[2] = 8002

只需要在类文件中声明一个数组就可以获取了:

private String[] ports ;

2.4、动态注入

前面几小节讲解的都是静态文件的注入,Spring Boot也还支持动态文件的注入,这里时候的动态文件的注入是指的通过代码来进行注入。要实现注入动态文件需要一个接口名叫EnvironmentPostProcessor的支持。EnvironmentPostProcessor接口的主要作用就是在Bean的装配期进行回调。

比如说我们在/Users/aa/Downloads/目录下有个app.properties的文件,这个文件是需要加载到Spring Boot中的,那么我们可以这样做

  1. 在/Users/aa/Downloads/app.properties文件中输入下面的属性
    spring.name=zhangsanaaa

  2. 声明一个实现了EnvironmentPostProcessor接口的类

package com.dragon.config;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.stereotype.Component;

@Component
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        try(InputStream input = new FileInputStream("/Users/aa/Downloads/app.properties")){
            Properties source = new Properties();
            source.load(input); 
            //PropertiesPropertySource构造函数接收2个参数。第一个是取个名称,第二个是数据源
            PropertiesPropertySource propertySource = new PropertiesPropertySource("my", source);
            environment.getPropertySources().addLast(propertySource);
        }catch(IOException e){

        }
    }
}

3、启动类读取
然后我们在启动类读取这个类.

@SpringBootApplication
public class SpringBootConfigApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext application = SpringApplication.run(SpringBootConfigApplication.class, args);
        System.out.println(application.getEnvironment().getProperty("spring.name"));
        application.close();
    }
}

我们的理想是从/Users/aa/Downloads/app.properties这个文件中读取spring.name的属性。但是很遗憾的是取不到该值的。

我们查看EnvironmentPostProcessor的源码会发现下面的注释:

<p>
 * EnvironmentPostProcessor implementations have to be registered in
 * {@code META-INF/spring.factories}, using the fully qualified name of this class as the
 * key.
 * <p>

也就是说EnvironmentPostProcessor的实现类必须注册在META-INF/spring.factories文件中。

4、注册EnvironmentPostProcessor实现类

我们在src/main/resources里面新建一个名词为META-INF的文件夹,再新建一个名称为spring.factories的文件,然后在该文件中加入下面的内容:

org.springframework.boot.env.EnvironmentPostProcessor=com.dragon.config.MyEnvironmentPostProcessor

然后再启动SpringBootConfigApplication就可以看到如下的信息
2、Spring Boot中属性的获取
之所以要加入spring.factories文件,是因为EnvironmentPostProcessor是Spring Boot的processor,而不是Spring的,是Spring原生不支持的。

通过了上面的几个步骤,我们就实现了动态注入。这种方式的好处是可以将配置文件集中管理,我们只需要指定配置文件的路径即可,可以实现多个工程的配置文件集中管理,而不需要各个工程各自维护一个配置文件。然后各个工程去相应的目录下读取即可。也可以通过HttpClient将远程的配置文件读取进来。(有点类似Spring Cloud的config-server的功能)

2.5、Profile

一般来说,都会有本地环境、测试环境和公网环境。那么不同的环境对应的配置文件肯定不一样的。这里的Profile就是指的不同的环境。

假设我们的classpath下面有application-test.properties、application-prod.properties这2个配置文件,代表了测试和正式环境,那么我们如何来加载不同的配置环境呢?

可以通过程序指定的代码实现

@SpringBootApplication
public class SpringBootConfigApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(SpringBootConfigApplication.class);
        application.setAdditionalProfiles("test");

        ConfigurableApplicationContext context = application.run(args);
        System.out.println(context.getEnvironment().getProperty("profile"));
    }
}

通过application.setAdditionalProfiles(“test”);就可以指定环境为test环境,那么加载的就是application-test.properties。

除了通过代码的方式,还可以通过spring.application.active来指定特定的环境。比如说–spring.profiles.active=test。

相关标签: spring-boot