您的位置:首页 > 编程语言 > Java开发

2、Spring Boot中属性的获取

2018-01-30 09:07 211 查看
在本节我们来讨论下如何获取配置文件里面的属性

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();
}
}


将会有如下的打印



在上面的示例中,我们将@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种设置默认值,我们还有下面的方式可以设置默认值

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();
}
}


运行该类,其打印如下



也就是说通过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,那么很显然这种情况默认是无法启动的。比如说我们的目录结构如下



在我们打成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中的,那么我们可以这样做

在/Users/aa/Downloads/app.properties文件中输入下面的属性

spring.name=zhangsanaaa

声明一个实现了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就可以看到如下的信息



之所以要加入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