在项目开发过程中,有必要使用一些灰色规则(即仅用于开发使用过程中的逻辑控制变量)。
比如,本地开发中,一些业务逻辑需要调用第三方代码,但又在本地调不通,怎么办。只能通过 if(本地开发) {mock数据或直接不调用} else {实际三方接口调用}。
这种方式可以使用@Value注解读取环境变量的方式来实现。
@Value属于spring的注解,在spring-beans包下,可以在 字段 或 方法参数 或 构造函数参数 上使用,通常用于属性注入。支持SpEL (Spring Expression Language)表达式来注入值,同时也支持属性占位符注入值。
使用@Value前提:
不能直接作用于静态变量(static);
不能直接作用于常量(final);
不能在非注册的类中使用(类需要被注册在spring上下文中,如用@Service,@RestController,@Component等);
使用这个类时,只能通过依赖注入的方式,用new的方式是不会自动注入这些配置的
@Value("${spring.application.name:somnus}") 代表的是假如application当中读不到值,那么就使用somnus。这样可以完全避免没有设置值而启动报错的问题。当然也可以不设置默认值,比如@Value("${spring.application.name:}") 这样同样可以避免没有设置值启动报错的问题!
使用@Value(“${环境变量名}”)就可以直接读取到操作系统的环境变量,就算在properties或者yaml中指定同名属性值也会被系统环境变量值所覆盖,所以在平常自定义属性时避免与系统环境变量重名,最好加上前缀。
笔者定义了这个字段注解
@Value("${test.ptVerify:}")
private String pressureTestVerify;
但是又不想在 application.yaml中定义,想直接通过 环境变量注入。
这里的问题在于,这里的ptVerify是 驼峰命名[破涕为笑],又有点号
在k8s的configMap里,先定义了
test.ptVerify,发现不行(在控制台也查不到这个环境变量,应该是 环境变量里不允许有 点)
test_ptVerify 不行,spring不识别
test_pt_verify 不行
最后可以工作的为
TEST_PTVERIFY
即全大写形式
SpringBoot的解释如下:
Binding From Environment Variables
Most operating systems impose strict rules around the names that can be used for environment variables. For example, Linux shell variables can contain only letters (a to z or A to Z), numbers (0 to 9) or the underscore character (_). By convention, Unix shell variables will also have their names in UPPERCASE.
Spring Boot’s relaxed binding rules are, as much as possible, designed to be compatible with these naming restrictions.
To convert a property name in the canonical-form to an environment variable name you can follow these rules:
Replace dots (.) with underscores (_).
Remove any dashes (-).
Convert to uppercase.
For example, the configuration property spring.main.log-startup-info would be an environment variable named SPRING_MAIN_LOGSTARTUPINFO.
debug了下 代码,相应的处理逻辑在类SystemEnvironmentPropertySource
中
protected final String resolvePropertyName(String name) {
Assert.notNull(name, "Property name must not be null");
String resolvedName = checkPropertyName(name);
if (resolvedName != null) {
return resolvedName;
}
String uppercasedName = name.toUpperCase();
if (!name.equals(uppercasedName)) {
resolvedName = checkPropertyName(uppercasedName);
if (resolvedName != null) {
return resolvedName;
}
}
return name;
}
@Nullable
private String checkPropertyName(String name) {
// Check name as-is
if (this.source.containsKey(name)) {
return name;
}
// Check name with just dots replaced
String noDotName = name.replace('.', '_');
if (!name.equals(noDotName) && this.source.containsKey(noDotName)) {
return noDotName;
}
// Check name with just hyphens replaced
String noHyphenName = name.replace('-', '_');
if (!name.equals(noHyphenName) && this.source.containsKey(noHyphenName)) {
return noHyphenName;
}
// Check name with dots and hyphens replaced
String noDotNoHyphenName = noDotName.replace('-', '_');
if (!noDotName.equals(noDotNoHyphenName) && this.source.containsKey(noDotNoHyphenName)) {
return noDotNoHyphenName;
}
// Give up
return null;
}
组件类,@Value必须在SpringBoot的组件中使用
@Component
public class ProfileValueInit {
@Value("${spring.profiles.active:}")
private String profile;
@Value("${test.verify:}")
private String verifyTest;
@Value("${test.ptVerify:}")
private String pressureTestVerify;
@PostConstruct
public void init() {
if (profile != null && profile.contains("local")) {
ProfileUtils.MOCK_VALUE = true;
}
if ("true".equals(verifyTest)) {
ProfileUtils.TEST_VERIFY = true;
}
if ("true".equals(pressureTestVerify)) {
ProfileUtils.PRESSURE_TEST_VERIFY = true;
}
}
}
方法类
public class ProfileUtils {
public static boolean MOCK_VALUE;
public static boolean TEST_VERIFY;
public static boolean PRESSURE_TEST_VERIFY;
public static boolean isMockEnv() {
return MOCK_VALUE;
}
public static boolean isTestVerify() {
return TEST_VERIFY;
}
public static boolean isPressureTestVerify() {
return PRESSURE_TEST_VERIFY;
}
}
业务类
// 压测模拟
boolean pt = ProfileUtils.isPressureTestVerify();
if (pt) {
//做模拟逻辑处理
}
使用set | grep PT
查看环境变量,发现有环境变量TEST_PTVERIFY=true
,那么以上代码则会生效。