前言
为了业务需求改变的时候,尽量少的修改代码,同时增加代码的重用性, 我们通常把一些数据以配置文件的方式配置,而不是写死在代码中.
既然如此,如何读取配置文件中的自定义参数,是很有必要了解的.
下面我将介绍几种方式,本文是基于SpringBoot而言的,配置文件使用的是yml,和xml是一样的,只是书写格式不同
方式一: @Value
application.yml配置文件
test:
age: 18
name: zuoyueer
lover: 美女
测试类
package com.zuoyueer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Zuoyueer
* Date: 2020/1/13
* Time: 21:58
* @projectName SpringBoot
* @description: 测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ReadConfigTest {
@Value("${test.name}")
public String name;
@Value("${test.age}")
private static int age; //注意这里加了static修饰变量
@Value("${test.lover}")
private String lover;
@Test
public void testValue(){
System.out.println(name + " " + age + " " + lover);
}
}
运行结果
zuoyueer 0 美女
结论:
- 在SpringBoot中使用@Value注解可以读取到配置文件中的自定义数据
- 但是@Value只能给普通变量赋值,不能给静态变量赋值( 不会报错,但是读取不到数据,结果显示0是变量的默认值 )
- 属性的范围权限无所谓,可以public,也可以private
如果自定义的数据一定要赋值给静态变量,怎么办? 别着急,强大的SpringBoot当然有办法:
package com.zuoyueer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Zuoyueer
* Date: 2020/1/13
* Time: 21:58
* @projectName SpringBoot
* @description: 测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ReadConfigTest {
@Value("${test.name}")
public String name;
// 声明一个静态变量
private static int age;
@Value("${test.lover}")
private String lover;
//给静态变量增加一个非静态的set方法,注意需要把@Value注解写到对应的set方法上
@Value("${test.age}")
public void setAge(int age){ // set方法的形参名随便
ReadConfigTest.age=age;
}
@Test
public void testValue(){
System.out.println(name + " " + age + " " + lover);
}
}
输出结果:
zuoyueer 18 美女
结论
- 为需要设值的静态变量,增加一个公共的set方法,@Value注解添加到set方法上, 就能给静态变量赋值
- 但是应该避免使用这样做,因为Spring不适合使用静态注入,更好的方案在后面
- 补充一点, 变量不能被final修饰,这这个很好理解,我也就不单独说明了
如果变量很多的话,每次用都要写一大堆,有没有好的解决方案呢 ? 有的
我们创建一个类ConfigBeanValue,把变量都放到这个类中,代码如下
package com.zuoyueer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author Zuoyueer
* Date: 2020/1/13
* Time: 22:41
* @projectName SpringBoot
* @description: 统一管理自定义的配置
*/
@Component
public class ConfigBeanValue {
@Value("${test.name}")
private String name;
@Value("${test.age}")
private int age;
@Value("${test.lover}")
private String lover;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getLover() {
return lover;
}
}
测试
package com.zuoyueer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Zuoyueer
* Date: 2020/1/13
* Time: 21:58
* @projectName SpringBoot
* @description: 测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ReadConfigTest {
@Autowired
private ConfigBeanValue configBeanValue;
@Test
public void testConfigBeanValue() {
System.out.println(configBeanValue.getName() + " " + configBeanValue.getAge() + " " + configBeanValue.getLover());
}
}
输出结果:
zuoyueer 18 美女
结论:
- 配置类必须注册到spring容器中,所以需要添加@Component注解
- 之所以提供get方法,是因为变量是私有的,如果变量是public,那么就不需要get方法了
- 使用的时候直接注入配置类对象, 就能随心所欲的使用该类中配置好了的属性了
注意: 如果@Value所包含的键名在application.yml配置文件中不存在的话,会抛出异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configBeanValue': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'test.age' in value "${test.age}"
方式二: Environment
配置文件同上,略
测试类
package com.zuoyueer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Zuoyueer
* Date: 2020/1/13
* Time: 21:58
* @projectName SpringBoot
* @description: 测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ReadConfigTest {
@Autowired
private Environment environment;
@Test
public void method() {
String age = environment.getProperty("test.age");
String name = environment.getProperty("test.name");
String lover = environment.getProperty("test.lover");
System.out.println(name + " " + age + " " + lover);
}
}
输出结果
zuoyueer 18 美女
结论:
- 使用的时候直接注入Environment对象,然后使用getProperty方法获取配置文件的数据
- getProperty方法的参数是键名, 返回类型是String, 如果希望使用数字类型,可以自己转换下
- 如果获取的是配置文件中没有的数据,那么和@Value一样,会报错
方式三: @ConfigurationProperties
配置文件同上, 略
编写配置类
package com.zuoyueer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author Zuoyueer
* Date: 2020/1/14
* Time: 0:10
* @projectName SpringBoot
* @description: ConfigurationProperties绑定配置数据到javaBean中
*/
@Component
@ConfigurationProperties(prefix = "test")
@PropertySource(value = "application.yml")
public class ConfigBeanProp {
private String name;
private int age;
private String lover;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getLover() {
return lover;
}
public void setLover(String lover) {
this.lover = lover;
}
}
@Component 表示将该类标识为Bean
@ConfigurationProperties(prefix = “demo”)用于绑定属性,其中prefix表示所绑定的属性的前缀。
@PropertySource(value = “config.properties”)表示配置文件路径
测试类
在这里插入代码片
读取普通文件中的数据,比如txt文件
第一种:
ClassPathResource classPathResource = new ClassPathResource("excleTemplate/test.xlsx");
InputStream inputStream =classPathResource.getInputStream();
第二种:
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("excleTemplate/test.xlsx");
第三种:
InputStream inputStream = this.getClass().getResourceAsStream("/excleTemplate/test.xlsx");
第四种:
File file = ResourceUtils.getFile("classpath:excleTemplate/test.xlsx");
InputStream inputStream = new FileInputStream(file);
前三种原理一样,都是类加载器实现的,
据说第四种在生产环境中会出问题,有待测试,保险起见,还是用前三种吧