一.应用场景
使用Spring Boot开发,经常需要自定义配置属性,例如系统全局属性,或者外部调用的常量属性等,那么这些配置属性应该放在哪里比较合适?怎么读取并在代码中使用呢?
二. 属性配置
在Spring Boot中,有两种常用的配置文件格式:properties和yml。下面总结了几种常见的属性配置和读取方式:
- 直接使用JDK自带的 java.util.ResourceBundle
JDK本身提供了 java.util.ResourceBundle 工具类可以用于读取properties配置文件。
package com.hong.util;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* @author wanghong
* @date 2019/06/14 22:48
* properties属性文件读取器
**/
public class PropertiesReader {
private ResourceBundle resourceBundle;
public PropertiesReader(String propertiesHolder) {
this.resourceBundle = ResourceBundle.getBundle(propertiesHolder, Locale.getDefault());
}
public String getLabel(String key) {
String label;
try {
label = new String(resourceBundle.getString(key).getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return label;
}
}
package com.hong.config;
import com.hong.util.PropertiesReader;
/**
* @author wanghong
* @date 2019/06/14 22:49
* App端属性配置常量类,绑定到类路径下app_config.properties资源
**/
public class AppConfig {
private static PropertiesReader getPropertiesVal = new PropertiesReader("app_config");
public static final String MY_PROP = getPropertiesVal.getLabel("myProp");
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest {
@Test
public void testConfig(){
System.out.println(AppConfig.MY_PROP); //123456
}
}
- @ConfigurationProperties
package com.hong.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/14 23:08
**/
@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfig2 {
private String version;
}
package com.hong.controller;
import com.hong.config.AppConfig2;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wanghong
* @date 2019/06/14 23:14
**/
@Api(value = "测试控制器")
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private AppConfig2 appConfig2;
@ApiOperation(value = "属性读取测试")
@RequestMapping(value = "testConfig",method = RequestMethod.GET)
public String testConfig() {
String version = appConfig2.getVersion();
return version;
}
}
如果现在 application-dev.yml中也定义了该属性:
且 spring.profiles.active=dev,那么读取到的 version = 1.0.0
- @PropertySource
现在再来看另一种场景: 假如我在 app_config.properties中也定义了该属性:
如何让 AppConfig2中读取的值是该文件中配置的值呢?这时就要手动指定属性源了。
package com.hong.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/14 23:08
**/
@Data
@Component
@PropertySource(value = { "classpath:app_config.properties" }, encoding = "UTF-8")
@ConfigurationProperties(prefix = "app")
public class AppConfig2 {
private String version;
}
但这里有一个坑,我本机Spring Boot使用的版本是2.0.4.RELEASE,如果在Spring Boot默认的全局属性文件application.yml或application.properties或application-{profile}.yml或application-{profile}.properties中存在与自定义属性配置文件中同名的属性,那么即使加了@PropertySource(value = { “classpath:app_config.properties” }, encoding = “UTF-8”)也不管用,最终读取到的还是默认全局属性文件中的值,当然一般出现这种情况,就是命名冲突的问题了,注意下就行了。
还有一种场景即使同一个属性值在不同的profile环境中值是不同的,如app_config.properties在dev环境下是1.1.0,在prod下是1.2.0,这时我们可以在resources目录下分别创建dev和prod两个文件夹,放置app_config.properties,然后设置下 @PropertySource的文件路径。
当然这种情况就是需要做到环境隔离了,如果是微服务的话,可以结合Spring Cloud使用分布式配置中心服务,将不同环境的配置放到git中方便修改和统一管理。
- @Value
package com.hong.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author wanghong
* @date 2019/06/15 0:36
**/
@Data
@Component
@PropertySource("classpath:app_config.properties")
public class AppConfig3 {
@Value("${app.version}")
private String version;
}
- @ConfigurationProperties与@Value的区别