Spring 引导:自定义属性配置和测试
Spring Boot: custom properties configuration and tests
我正在使用 Spring Boot 2.0 和默认的 application.yml
属性文件。我想将它拆分为单独的 属性 个文件,因为它变得很大。
我还想编写测试来检查属性的正确性:将出现在生产应用程序上下文(而不是测试上下文)中的值。
这是我的 属性 文件:src/main/resources/config/custom.yml
my-property:
value: 'test'
属性 class:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Data
@Configuration
@ConfigurationProperties(prefix = "my-property")
@PropertySource("classpath:config/custom.yml")
public class MyProperty {
private String value;
}
测试:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@EnableConfigurationProperties
public class MyPropertyTest {
@Autowired
private MyProperty property;
@Test
public void test() {
assertEquals("test", property.getValue());
}
}
但是测试失败并出现错误:
java.lang.AssertionError:
Expected :test
Actual :null
我还看到 属性 值是 null
当 运行 应用程序通过在 ApplicationRunner
中打印它时 null
。
当我对所有属性使用 application.yml
时,它在相同配置下运行良好。
如何正确配置属性和测试以使其正常工作?
Link 到 Github repo
@TestPropertySource
可以解决您的问题。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@TestPropertySource(locations="classpath:test.properties")
public class MyPropertyTest {
@Autowired
private MyProperty property;
@Test
public void test() {
assertEquals("test", property.getValue());
}
}
希望对您有所帮助。
如果这是您的确切代码,则表示您正在从错误的 属性 文件读取 属性。
将您的 属性 资源替换到此行。
@PropertySource("classpath:config/services.yml")
好吧,我找到了在我的应用程序中使用自定义 yaml 属性的正确方法。
问题是 Spring 不支持 yaml 文件,因为 @PropertySource
(link to issue). And here is a workaround how to deal with that described in spring documentation.
因此,要能够从您需要的 yaml 文件加载属性:
* 实施EnvironmentPostProcessor
* 要在 spring.factories
中注册
请访问此 github repo 以获取完整示例。
另外,非常感谢大家的支持!
我来晚了一点,但这可能也有帮助。作为答案提供的解决方案是迄今为止最好的方法,但这是我使用的替代方法
利用配置文件并修改 PropertySoucesPlaceHolderConfiguration bean 以根据配置文件加载必要的 属性 文件。它加载 application.properties 作为默认文件,但其他 属性 文件 -oauth_DEV 和 oauth_QA 根据配置文件集加载
@Bean
public PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurerconfigurer() {
System.out.println("Inside Placeholder bean");
PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer();
ClassPathResource cls1= new ClassPathResource("application.properties");
ClassPathResource cls2 = null;
Map<String, Object> propMap = ((ConfigurableEnvironment) ctx.getEnvironment()).getSystemProperties();
for(Map.Entry<String, Object> entrySet: propMap.entrySet()) {
System.out.println("Map.Key:"+entrySet.getKey()+" Map.valiue:"+entrySet.getValue());
}
List<String> profiles= Arrays.asList(ctx.getEnvironment().getActiveProfiles());
if(profiles == null || profiles.isEmpty()) {
if(!propMap.containsKey("spring.profiles.active")) {
cls2 = new ClassPathResource("oauth-default.properties");
} else {
cls2 = new ClassPathResource("oauth-"+propMap.get("spring.profiles.active")+".properties");
}
}else {
for(String profile:profiles) {
if(profile.equalsIgnoreCase("DEV")) {
cls2 = new ClassPathResource("oauth-DEV.properties");
}else if(profile.equalsIgnoreCase("QA")) {
cls2 = new ClassPathResource("oauth-QA.properties");
}else if (profile.equalsIgnoreCase("UAT")) {
cls2 = new ClassPathResource("oauth-UAT.properties");
}else if(profile.equalsIgnoreCase("PROD")){
cls2 = new ClassPathResource("oauth-PROD.properties");
}else {
cls2 = new ClassPathResource("oauth-default.properties");
}
}
}
cfg.setLocations(cls1,cls2);
//cfg.setPlaceholderPrefix("#{");
return cfg;
}
然后创建另一个根据前缀读取属性的bean - "security.oauth2.client"
@Configuration
@ConfigurationProperties(prefix="security.oauth2.client")
public class OauthSecurityConfigurationDto {
private String clientId;
private String clientSecret;
private String scope;
private String accessTokenUri;
private String userAuthorizationUri;
private String grantType;
private String resourceIds;
private String registeredRedirectUri;
private String preEstablishedRedirectUri;
private String useCurrentUri;
private String userInfoUri;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getAccessTokenUri() {
return accessTokenUri;
}
public void setAccessTokenUri(String accessTokenUri) {
this.accessTokenUri = accessTokenUri;
}
public String getUserAuthorizationUri() {
return userAuthorizationUri;
}
public void setUserAuthorizationUri(String userAuthorizationUri) {
this.userAuthorizationUri = userAuthorizationUri;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public String getResourceIds() {
return resourceIds;
}
public void setResourceIds(String resourceIds) {
this.resourceIds = resourceIds;
}
public String getRegisteredRedirectUri() {
return registeredRedirectUri;
}
public void setRegisteredRedirectUri(String registeredRedirectUri) {
this.registeredRedirectUri = registeredRedirectUri;
}
public String getPreEstablishedRedirectUri() {
return preEstablishedRedirectUri;
}
public void setPreEstablishedRedirectUri(String preEstablishedRedirectUri) {
this.preEstablishedRedirectUri = preEstablishedRedirectUri;
}
public String getUseCurrentUri() {
return useCurrentUri;
}
public void setUseCurrentUri(String useCurrentUri) {
this.useCurrentUri = useCurrentUri;
}
public String getUserInfoUri() {
return userInfoUri;
}
public void setUserInfoUri(String userInfoUri) {
this.userInfoUri = userInfoUri;
}
}
记住 setter 很重要,因为 ConfigurationProperties
只有在定义了 getter 和 setter 时才会将值加载到 class 的属性中
现在我们可以在任何需要的地方自动装配依赖项并使用 属性.
我正在使用 Spring Boot 2.0 和默认的 application.yml
属性文件。我想将它拆分为单独的 属性 个文件,因为它变得很大。
我还想编写测试来检查属性的正确性:将出现在生产应用程序上下文(而不是测试上下文)中的值。
这是我的 属性 文件:src/main/resources/config/custom.yml
my-property:
value: 'test'
属性 class:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Data
@Configuration
@ConfigurationProperties(prefix = "my-property")
@PropertySource("classpath:config/custom.yml")
public class MyProperty {
private String value;
}
测试:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@EnableConfigurationProperties
public class MyPropertyTest {
@Autowired
private MyProperty property;
@Test
public void test() {
assertEquals("test", property.getValue());
}
}
但是测试失败并出现错误:
java.lang.AssertionError:
Expected :test
Actual :null
我还看到 属性 值是 null
当 运行 应用程序通过在 ApplicationRunner
中打印它时 null
。
当我对所有属性使用 application.yml
时,它在相同配置下运行良好。
如何正确配置属性和测试以使其正常工作?
Link 到 Github repo
@TestPropertySource
可以解决您的问题。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@TestPropertySource(locations="classpath:test.properties")
public class MyPropertyTest {
@Autowired
private MyProperty property;
@Test
public void test() {
assertEquals("test", property.getValue());
}
}
希望对您有所帮助。
如果这是您的确切代码,则表示您正在从错误的 属性 文件读取 属性。
将您的 属性 资源替换到此行。
@PropertySource("classpath:config/services.yml")
好吧,我找到了在我的应用程序中使用自定义 yaml 属性的正确方法。
问题是 Spring 不支持 yaml 文件,因为 @PropertySource
(link to issue). And here is a workaround how to deal with that described in spring documentation.
因此,要能够从您需要的 yaml 文件加载属性:
* 实施EnvironmentPostProcessor
* 要在 spring.factories
请访问此 github repo 以获取完整示例。
另外,非常感谢大家的支持!
我来晚了一点,但这可能也有帮助。作为答案提供的解决方案是迄今为止最好的方法,但这是我使用的替代方法
利用配置文件并修改 PropertySoucesPlaceHolderConfiguration bean 以根据配置文件加载必要的 属性 文件。它加载 application.properties 作为默认文件,但其他 属性 文件 -oauth_DEV 和 oauth_QA 根据配置文件集加载
@Bean
public PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurerconfigurer() {
System.out.println("Inside Placeholder bean");
PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer();
ClassPathResource cls1= new ClassPathResource("application.properties");
ClassPathResource cls2 = null;
Map<String, Object> propMap = ((ConfigurableEnvironment) ctx.getEnvironment()).getSystemProperties();
for(Map.Entry<String, Object> entrySet: propMap.entrySet()) {
System.out.println("Map.Key:"+entrySet.getKey()+" Map.valiue:"+entrySet.getValue());
}
List<String> profiles= Arrays.asList(ctx.getEnvironment().getActiveProfiles());
if(profiles == null || profiles.isEmpty()) {
if(!propMap.containsKey("spring.profiles.active")) {
cls2 = new ClassPathResource("oauth-default.properties");
} else {
cls2 = new ClassPathResource("oauth-"+propMap.get("spring.profiles.active")+".properties");
}
}else {
for(String profile:profiles) {
if(profile.equalsIgnoreCase("DEV")) {
cls2 = new ClassPathResource("oauth-DEV.properties");
}else if(profile.equalsIgnoreCase("QA")) {
cls2 = new ClassPathResource("oauth-QA.properties");
}else if (profile.equalsIgnoreCase("UAT")) {
cls2 = new ClassPathResource("oauth-UAT.properties");
}else if(profile.equalsIgnoreCase("PROD")){
cls2 = new ClassPathResource("oauth-PROD.properties");
}else {
cls2 = new ClassPathResource("oauth-default.properties");
}
}
}
cfg.setLocations(cls1,cls2);
//cfg.setPlaceholderPrefix("#{");
return cfg;
}
然后创建另一个根据前缀读取属性的bean - "security.oauth2.client"
@Configuration
@ConfigurationProperties(prefix="security.oauth2.client")
public class OauthSecurityConfigurationDto {
private String clientId;
private String clientSecret;
private String scope;
private String accessTokenUri;
private String userAuthorizationUri;
private String grantType;
private String resourceIds;
private String registeredRedirectUri;
private String preEstablishedRedirectUri;
private String useCurrentUri;
private String userInfoUri;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getAccessTokenUri() {
return accessTokenUri;
}
public void setAccessTokenUri(String accessTokenUri) {
this.accessTokenUri = accessTokenUri;
}
public String getUserAuthorizationUri() {
return userAuthorizationUri;
}
public void setUserAuthorizationUri(String userAuthorizationUri) {
this.userAuthorizationUri = userAuthorizationUri;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public String getResourceIds() {
return resourceIds;
}
public void setResourceIds(String resourceIds) {
this.resourceIds = resourceIds;
}
public String getRegisteredRedirectUri() {
return registeredRedirectUri;
}
public void setRegisteredRedirectUri(String registeredRedirectUri) {
this.registeredRedirectUri = registeredRedirectUri;
}
public String getPreEstablishedRedirectUri() {
return preEstablishedRedirectUri;
}
public void setPreEstablishedRedirectUri(String preEstablishedRedirectUri) {
this.preEstablishedRedirectUri = preEstablishedRedirectUri;
}
public String getUseCurrentUri() {
return useCurrentUri;
}
public void setUseCurrentUri(String useCurrentUri) {
this.useCurrentUri = useCurrentUri;
}
public String getUserInfoUri() {
return userInfoUri;
}
public void setUserInfoUri(String userInfoUri) {
this.userInfoUri = userInfoUri;
}
}
记住 setter 很重要,因为 ConfigurationProperties
只有在定义了 getter 和 setter 时才会将值加载到 class 的属性中
现在我们可以在任何需要的地方自动装配依赖项并使用 属性.