Java Spring是否遵循应用程序配置的命名约定?
问题: 在application.properties中定义的配置不被环境变量覆盖 我在spring配置方面遇到了一个奇怪的问题,即在Java Spring是否遵循应用程序配置的命名约定?,java,spring,spring-boot,Java,Spring,Spring Boot,问题: 在application.properties中定义的配置不被环境变量覆盖 我在spring配置方面遇到了一个奇怪的问题,即在应用程序中定义的配置。当以特定方式命名配置时,环境变量不会覆盖属性。正如操作系统中提到的,环境变量优先于应用程序.属性,但当配置定义为myExternal\u url时不会发生这种情况,但当配置定义为my\u external\u url(在下面的示例代码中,我们需要在ApplicationProperties.java和application.propertie
应用程序中定义的配置。当以特定方式命名配置时,环境变量不会覆盖属性。正如操作系统中提到的,环境变量优先于应用程序.属性
,但当配置定义为myExternal\u url
时不会发生这种情况,但当配置定义为my\u external\u url
(在下面的示例代码中,我们需要在ApplicationProperties.java
和application.properties
中将配置更改为my\u external\url
)
示例代码-
@SpringBootApplication
public class ConfigApplication implements ApplicationRunner {
@Autowired private ApplicationProperties applicationProperties;
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
@Override
public void run(ApplicationArguments arg0) {
System.out.println("External URL = " + applicationProperties.getMyExternalUrl());
}
}
应用程序Bean配置-
@Configuration
public class AppConfig {
@Bean
@ConfigurationProperties(prefix = "")
public ApplicationProperties applicationProperties() {
return new ApplicationProperties();
}
}
应用程序属性
类-
public class ApplicationProperties {
@Value("${myExternal_url}")
private String myExternalUrl;
public String getMyExternalUrl() {
return this.myExternalUrl;
}
public void setMyExternalUrl(String myExternalUrl) {
this.myExternalUrl = myExternalUrl;
}
}
application.properties
:
myExternal_url=external_url_env_application_properties
这可能是什么原因
编辑-添加渐变
梯度配置
plugins {
id 'org.springframework.boot' version '2.4.0-M1'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.6'
annotationProcessor 'org.projectlombok:lombok:1.18.6'
}
test {
useJUnitPlatform()
}
编辑2
跟踪日志显示myExternal_url已从环境变量正确解析。然后Spring通过调用AutowiredNotationBeanPostProcessor
尝试解析自动关联依赖项“applicationProperties
”,然后值被application.properties值覆盖(屏幕截图)
- 我无法在
2.3.1.RELEASE
中重现您的问题,它正在按预期工作,并被我的环境变量覆盖
- 但是,我没有看到spring文档中说,
@Value(${myExternal_url}”)
也使用松弛绑定。我看到的只是@ConfigurationProperties
将使用松弛绑定
- 因此,我将按如下方式更新您的类(即使它在
2.3.1.RELEASE
中使用和不使用它)@Value
注释已删除
- 请注意,这两个属性仍将存在于
环境中
,但当它绑定时,似乎会决定一个属性是否覆盖另一个属性。您可以通过打印看到这一点。这里我从应用程序上下文
获取环境
,但您可以自动连线
环境
并进行测试
- 为了确认上面的一点,即只有
@ConfigurationProperties
支持轻松绑定,但不支持@Value
Spring确实支持某种松散绑定形式的命名约定(正如@Kavithakaran kanapathipillai所指出的)。对于和@Value注释,Spring尝试按照使用中定义的顺序解析配置源中的变量
如回答@夢のの夢 - spring使用@Value(${myExternal\u url}”)
与环境变量正确匹配属性,但后来被@ConfigurationProperties(prefix=”“)
覆盖
由于beanApplicationProperties
被定义为@ConfigurationProperties(prefix=”“)
,Spring尝试将变量与配置源匹配(使用宽松绑定),并在application.propertied变量myexternalur
中找到匹配项,并覆盖使用@Value(${myExternal u url})解析的属性
。问题在于同时使用@Value
和@ConfigurationProperties(prefix=”“)
旁注-@Value
支持并且Spring建议使用kebab大小写定义@Value属性名
从文件-
如果确实要使用@Value,建议您参考属性
使用其规范形式的名称(烤肉串大小写仅使用小写)
这将允许Spring Boot使用与它相同的逻辑
当放松绑定@ConfigurationProperties时。例如,
@值(“{demo.item-price}”)将拾取demo.item-price和
application.properties文件中的demo.itemPrice表单,以及
系统环境中的DEMO_ITEMPRICE。如果使用
@值(“{demo.itemPrice}”),改为demo.item-price和demo\u itemPrice
不会被考虑
TL;DR@Value
从注入的系统变量中具有正确的myExternal\u Url
,但其值稍后由@ConfigurationProperties
设置
跟踪日志是正确的,因为Spring的排序将把systemEnvironment
放在propertySource列表中classpath:/application.properties
之前
您遇到的问题是由于同时使用@Value
和@ConfigurationProperties
来注入/绑定您的属性。
假设这些是您提供的值:
system:
myExternal_Url: foo
my_external_url: bar
applications.properties:
myExternal_url: aaa
在应用程序属性中:
@Value("${myExternal_url}")
private String myExternalUrl; // injected with foo
myExternalUrl
正确地注入了值(foo
)您在环境变量中定义了。但是,@ConfigurationProperties
使用setter方法将后的值绑定到。由于它使用宽松的绑定,它会检查myExternalUrl
的不同变体,它首先查找系统变量中的内容,并发现myExternal\u url
(驼峰和下划线)不是一种宽松的绑定形式,但my_external\u url
(仅下划线)是。因此my_external\u url
的值提供给setter:
public void setMyExternalUrl(String myExternalUrl) { // bar
this.myExternalUrl = myExternalUrl; // myExternalUrl is reassigned from foo to bar
}
因此,应该清楚的是,@Value
将始终被覆盖,因为@ConfigurationProperties
在之后绑定值。只需:
public class ApplicationProperties {
private String myExternalUrl;
...
然后在您的系统中定义一个绑定表单-MY_EXTERNAL\u URL
、MY EXTERNAL URL
、或MY_EXTERNAL\u URL
(可能还有更多)-然后在应用程序中使用一致的大小写。yml以防您不需要系统变量
my-external-url=aaa
旁注。建议您使用表单MY\u EXTERNAL\u URL
作为系统环境
@Value("${myExternal_url}")
private String myExternalUrl; // injected with foo
public void setMyExternalUrl(String myExternalUrl) { // bar
this.myExternalUrl = myExternalUrl; // myExternalUrl is reassigned from foo to bar
}
public class ApplicationProperties {
private String myExternalUrl;
...
my-external-url=aaa