![](/img/trans.png)
[英]Spring Data JPA native query does not follow naming convention with projections
[英]Does Spring follow any naming convention for application configuration?
问题:在 application.properties 中定义的配置未被环境变量覆盖。
我遇到了 spring 配置的奇怪问题,因为application.properties
中定义的配置在以特定方式命名配置时不会被环境变量覆盖。 正如在外部化配置中提到的那样,操作系统环境变量优先于application.properties
,但是当配置定义为myExternal_url
时不会发生这种情况,但当配置定义为my_external_url
时它会起作用(在下面的示例代码中,我们需要在ApplicationProperties.java
中将配置更改为my_external_url
ApplicationProperties.java
和application.properties
)
示例代码 -
@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();
}
}
ApplicationProperties
属性 class -
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
这可能是什么原因?
编辑 - 添加 gradle Gradle 配置
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 尝试通过调用AutowiredAnnotationBeanPostProcessor
来解决自动装配的依赖项“ applicationProperties
”,然后值被 application.properties 值覆盖(屏幕截图)。
o.s.c.e.PropertySourcesPropertyResolver : Found key 'myExternal_url' in PropertySource 'systemEnvironment' with value of type String
o.s.c.e.PropertySourcesPropertyResolver : Found key 'myExternal_url' in PropertySource 'environmentProperties' with value of type String
我无法在2.3.1.RELEASE
中重现您的问题,并且按预期工作,并被我的环境变量覆盖。
但是,我没有看到 spring 文档中提到, @Value("${myExternal_url}")
也使用宽松的绑定。 我所看到的是@ConfigurationProperties
将使用宽松的绑定。
所以我会更新你的 class 如下(即使它在2.3.1.RELEASE
中使用和不使用) @Value
注释已删除
public class ApplicationProperties {
private String myExternalUrl;
public String getMyExternalUrl() {
return this.myExternalUrl;
}
public void setMyExternalUrl(String myExternalUrl) {
this.myExternalUrl = myExternalUrl;
}
}
Environment
中,但是当它被绑定时,它似乎决定了一个是否覆盖另一个。 您可以通过打印看到这一点。 在这里,我从applicationContext
获取environment
,但您可以autowire
Environment
并测试它 System.out.println(context.getEnvironment()
.getProperty("myExternal_url"));
System.out.println(context.getEnvironment()
.getProperty("my_external_url"));
@ConfigurationProperties
支持宽松绑定,但不支持@Value
。 我创建了以下 class @Component
public class ValueInjection {
// This prints application properties.
@Value("${myExternal_url}")
private String myExternal_url;
// This prints the environment variable
@Value("${my_external_url}")
private String my_external_url;
// If you uncomment this the application will not start saying
// there is no such property.
//
// @Value("${myExternalUrl}")
// private String myExternalUrl;
// ... getters and setters
}
Spring 确实以轻松绑定的形式支持某种命名约定(正如@Kavithakaran Kanapathippillai 所指出的那样)。 在@ConfigurationProperties和@Value 注释的情况下,Spring 尝试按照Externalized Configuration using Relax binding中定义的顺序从配置源解析变量。
正如@梦のの梦的回答 - spring 使用带有环境变量的@Value("${myExternal_url}")
正确匹配属性,但后来被@ConfigurationProperties(prefix = "")
覆盖。
由于 bean ApplicationProperties
被定义为@ConfigurationProperties(prefix = "")
,Spring 尝试将变量与配置源匹配(使用宽松绑定)并在 application.properied 变量myExternalUrl
中找到匹配项,并覆盖使用@Value("${myExternal_url}")
。 问题在于同时使用@Value
和@ConfigurationProperties(prefix = "")
。
旁注 - @Value
支持有限的宽松绑定, Spring 建议使用 kebab-case 定义 @Value 属性名称。
从文档 -
如果您确实想使用@Value,我们建议您使用其规范形式(kebab-case 仅使用小写字母)引用属性名称。 这将允许 Spring Boot 使用与放松绑定 @ConfigurationProperties 时相同的逻辑。 例如,@Value("{demo.item-price}") 将从 application.properties 文件中获取 demo.item-price 和 demo.itemPrice forms,以及从系统环境中获取 DEMO_ITEMPRICE。 如果您改用 @Value("{demo.itemPrice}"),则不会考虑 demo.item-price 和 DEMO_ITEMPRICE。
TL;DR @Value
从注入的系统变量中具有正确的myExternal_Url
,但其值稍后由@ConfigurationProperties
设置。
跟踪日志是正确的,因为从 Spring 的排序会将systemEnvironment
放在 propertySource 列表中的classpath:/application.properties
之前。
您遇到的问题是因为同时使用@Value
和@ConfigurationProperties
来注入/绑定您的属性。 假设这些是您提供的值:
system:
myExternal_Url: foo
my_external_url: bar
applications.properties:
myExternal_url: aaa
在您的 ApplicationProperties 中:
@Value("${myExternal_url}")
private String myExternalUrl; // injected with foo
myExternalUrl
使用您在环境变量中定义的值 ( foo
) 正确注入。 但是, @ConfigurationProperties
使用 setter 方法绑定了之后的值。 由于它使用宽松的绑定,它会检查myExternalUrl
的不同变体,它首先查找系统变量中的内容并发现myExternal_url
(骆驼和下划线)不在宽松绑定 forms 之一中,然后my_external_url
(仅限下划线)是。 所以my_external_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;
...
然后在您的系统中定义绑定 forms - MY_EXTERNAL_URL
、 my-external-url
或my_external_url
(也许还有更多)之一。 然后在您的 application.yml 中使用一致的大小写,以防您不想要系统变量。
my-external-url=aaa
边注。 建议您使用MY_EXTERNAL_URL
形式作为系统环境变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.