在实际的项目开发过程中,我们经常需要将某些变量从代码里面抽离出来,放在配置文件里面,以便更加统一、灵活的管理服务配置信息。比如,数据库、eureka、zookeeper、redis、mq、kafka 等服务组件的连接参数配置,还有我们自定义的项目参数配置变量。 当然,实际上根据当前的业务需求,我们往往会自定义参数,然后注入到代码里面去,以便灵活使用! 今天,我们就一起来聊一聊 SpringBoot 项目在启用时,首先会默认加载 虽然说配置项都写在同一个配置文件没有问题,但是很多时候我们仍然希望能分开写,这样会比较清晰,比如 具体该如何实现呢,我们一起来看看! 2.1、通过 当我们想要在某个类里面注入某个变量,通过 例如 然后在对应的类里面,通过参数 使用 当然,如果我们不想让它抱错,我们可以给它一个缺省值 这样,SpringBoot 项目在启用时不会报错! 2.2、通过 某些场景下, 例如在 然后,创建一个配置类 读取数据的方式,也很简单,直接注入到对应的类里面就可以了 例如在 然后,创建一个配置类 读取数据的方式,与之类似! 例如在 然后,创建一个配置类 读取数据的方式,与之类似! 2.3、通过 正如我们最开始所介绍的,很多时间,我们希望将配置文件分卡写,比如 这种自定义的配置文件,我们应该如何加载到 其实方法也很简单,通过 首先,我们在 在 读取数据的方式,与之类似! 如果我们只是在业务中需要用到自定义配置文件的值,这样引入并没有什么问题;但是如果某些自定义的变量,在项目启动的时候需要用到,这种方式会存在一些问题,原因如下: 翻译过来的意思就是说: 虽然在 因此,如果某些参数是启动项变量,建议将其定义在 或者,采用【自定义环境处理类】来实现配置文件的加载! 2.4、通过自定义环境处理类,实现配置文件的加载 实现方法也很简单,首先,创建一个实现自 接着,在 这种自定义环境处理类方式,相对会更佳灵活,首先编写一个通用的配置文件解析类,支持 2.5、最后,我们来介绍一下 在上文中,我们大部分都是以 那如果,我想单独解析 操作方式也很简单,以自定义的 然后,创建一个读取 读取数据的方式,与之类似! 本文主要围绕 SpringBoot 加载配置文件的几种实现方式,做了一次内容总结,如果有遗漏的地方,欢迎网友批评指出! 1、springBoot 官方文档一、简介
SpringBoot
加载配置文件的几种玩法,如果有遗漏,欢迎留言!bootstrap.properties
或者bootstrap.yml
这两个配置文件(这两个优先级最高);接着会加载application.properties
或application.yml
;如果何配置了spring.profiles
这个变量,同时还会加载对应的application-{profile}.properties
或者application-{profile}.yml
文件,profile
为对应的环境变量,比如dev
,如果没有配置,则会加载profile=default
的配置文件。zookeeper
的配置写在zookeeper.properties
,数据库相关的配置写在datasource.properties
等等,因此就需要设置加载外部配置文件!二、代码实践
@value
注解实现参数加载@value
注解就可以简单实现参数的注入!application.properties
文件里,配置一个config.name
的变量key
,值为zhangsan
//参数定义
config.name=zhangsan@value
注入即可!@RestController
public class HelloController {
@Value("${config.name}")
private String config;
@GetMapping("config")
public String config(){
return JSON.toJSONString(config);
}
}@value
注解注入配置,通常情况下有个要求就是,注解里面的变量,必须在application.properties
文件里面事先定义好,否则启动报错!xxx
,比如:@Value("${config.name:xxx}")
private String config;@ConfigurationProperties
注解实现参数加载@value
注解并不能满足我们所有的需求,比如参数配置的数据类型是一个对象或者数组,这个时候才用@ConfigurationProperties
会是一个比较好的选择!application.properties
文件里,当我们想配置一个对象类型的参数,我们可以这样操作!//参数定义
config2.name=demo_1
config2.value=demo_value_1Config2
,用于将定义的变量映射到配置类里面。@Component
@ConfigurationProperties(prefix = "config2")
public class Config2 {
public String name;
public String value;
//...get、set
}@RestController
public class HelloController {
@Autowired
private Config2 config2;
@GetMapping("config2")
public String config2(){
return JSON.toJSONString(config2);
}
}Map
类型的参数application.properties
文件里,当我们想配置一个 Map 类型的参数,我们可以这样操作!//参数定义
config3.map1.name=demo_id_1_name
config3.map1.value=demo_id_1_value
config3.map2.name=demo_id_2_name
config3.map2.value=demo_id_2_valueConfig3
,用于将定义的变量映射到配置类里面。@Component
@ConfigurationProperties(prefix = "config3")
public class Config3 {
private Map<String, String> map1 = new HashMap<>();
private Map<String, String> map2 = new HashMap<>();
//...get、set
}@RestController
public class HelloController {
@Autowired
private Config3 config3;
@GetMapping("config3")
public String config3(){
return JSON.toJSONString(config3);
}
}List
类型的参数application.properties
文件里,当我们想配置一个 List 类型的参数,我们可以这样操作!//参数定义
config4.userList[0].enable=maillist_1_enable
config4.userList[0].name=maillist_1_name
config4.userList[0].value=maillist_1_value
config4.userList[1].enable=maillist_2_enable
config4.userList[1].name=maillist_2_name
config4.userList[1].value=maillist_2_value
config4.userList[2].enable=maillist_3_enable
config4.userList[2].name=maillist_3_name
config4.userList[2].value=maillist_3_valueConfig4
,用于将定义的变量映射到配置类里面。@Component
@ConfigurationProperties(prefix = "config4")
public class Config4 {
private List<UserEntity> userList;
public List<UserEntity> getUserList() {
return userList;
}
public void setUserList(List<UserEntity> userList) {
this.userList = userList;
}
}public class UserEntity {
private String enable;
private String name;
private String value;
//...get、set
}@RestController
public class HelloController {
@Autowired
private Config4 config4;
@GetMapping("config4")
public String config4(){
return JSON.toJSONString(config4);
}
}@PropertySource
注解实现配置文件加载zookeeper
组件对应的服务配置文件是zookeeper.properties
,redis
组件对应的服务配置文件是redis.properties
等等。Spring
容器里面呢?@PropertySource
就可以实现!resources
资源文件夹下,创建两个配置文件test.properties
和bussiness.properties
,内容如下!test.properties
文件内容:aaa.a1=aa1123
aaa.a2=aa2123
aaa.a3=aa3123
aaa.a4=aa4123bussiness.properties
文件内容:bbbb.a1=bb1123
bbbb.a2=bb2123
bbbb.a3=bb3123
bbbb.a4=bb4123SpringBoot
启动类上加载配置文件即可!@SpringBootApplication
@PropertySource(value = {"test.properties","bussiness.properties"})
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}@RestController
public class HelloController {
@Value("${aaa.a2}")
private String a2;
@Value("${bbbb.a1}")
private String bbbbA1;
@GetMapping("a2")
public String a2(){
return JSON.toJSONString(a2);
}
@GetMapping("bbbbA1")
public String bbbbA1(){
return JSON.toJSONString(bbbbA1);
}
}@SpringBootApplication
上使用@PropertySource
似乎是在环境中加载自定义资源的一种方便而简单的方法,但我们不推荐使用它,因为SpringBoot
在刷新应用程序上下文之前就准备好了环境。使用@PropertySource
定义的任何键都加载得太晚,无法对自动配置产生任何影响。application.properties
或application.yml
文件里面,这样就不会有问题!EnvironmentPostProcessor
接口的类,然后自行加载配置文件。public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
//自定义配置文件
String[] profiles = {
"test.properties",
"bussiness.properties",
"blog.yml"
};
//循环添加
for (String profile : profiles) {
//从classpath路径下面查找文件
Resource resource = new ClassPathResource(profile);
//加载成PropertySource对象,并添加到Environment环境中
environment.getPropertySources().addLast(loadProfiles(resource));
}
}
//加载单个配置文件
private PropertySource<?> loadProfiles(Resource resource) {
if (!resource.exists()) {
throw new IllegalArgumentException("资源" + resource + "不存在");
}
if(resource.getFilename().contains(".yml")){
return loadYaml(resource);
} else {
return loadProperty(resource);
}
}
/**
* 加载properties格式的配置文件
* @param resource
* @return
*/
private PropertySource loadProperty(Resource resource){
try {
//从输入流中加载一个Properties对象
Properties properties = new Properties();
properties.load(resource.getInputStream());
return new PropertiesPropertySource(resource.getFilename(), properties);
}catch (Exception ex) {
throw new IllegalStateException("加载配置文件失败" + resource, ex);
}
}
/**
* 加载yml格式的配置文件
* @param resource
* @return
*/
private PropertySource loadYaml(Resource resource){
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource);
//从输入流中加载一个Properties对象
Properties properties = factory.getObject();
return new PropertiesPropertySource(resource.getFilename(), properties);
}catch (Exception ex) {
throw new IllegalStateException("加载配置文件失败" + resource, ex);
}
}
}resources
资源目录下,我们还需要创建一个文件META-INF/spring.factories
,通过spi
方式,将自定义环境处理类加载到Spring
处理器里面,当项目启动时,会自动调用这个类!#启用我们的自定义环境处理类
org.springframework.boot.env.EnvironmentPostProcessor=com.example.property.env.MyEnvironmentPostProcessorproperties
和yml
文件的读取,然后将其注入到Spring
容器里面,基本上可以做到一劳永逸!yml
文件读取properties
为案例进行介绍,可能有的人已经踩过坑了,在项目中使用@PropertySource
注解来加载yml
文件,结果启动直接报错,原因是@PropertySource
不支持直接解析yml
文件,只能解析properties
文件。yml
文件,也不想弄一个【自定义环境处理类】这种方式来读取文件,应该如何处理呢?blog.yml
文件为例!blog.yml
文件内容:pzblog:
name: helloWorldyml
文件的配置类@Configuration
public class ConfigYaml {
/**
* 加载YML格式自定义配置文件
* @return
*/
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("blog.yml"));
configurer.setProperties(yaml.getObject());
return configurer;
}
}@RestController
public class HelloController {
@Value("${pzblog.name}")
private String pzblogName;
@GetMapping("pzblogName")
public String pzblogName(){
return JSON.toJSONString(pzblogName);
}
}三、小结
四、参考