Spring Boot – 从application.yml注入映射

我有一个Spring的应用程序与以下application.yml – 基本上从这里采取:

 info: build: artifact: ${project.artifactId} name: ${project.name} description: ${project.description} version: ${project.version} 

我可以注入特定的值,例如

 @Value("${info.build.artifact}") String value 

然而,我想要注入整个地图,即像这样的东西:

 @Value("${info}") Map<String, Object> info 

那(或者类似的)是可能的吗? 显然,我可以直接加载yaml,但是想知道Spring是否已经支持某些东西。

您可以使用@ConfigurationProperties注入地图:

 import java.util.HashMap; import java.util.Map; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @EnableConfigurationProperties public class MapBindingSample { public static void main(String[] args) throws Exception { System.out.println(SpringApplication.run(MapBindingSample.class, args) .getBean(Test.class).getInfo()); } @Bean @ConfigurationProperties public Test test() { return new Test(); } public static class Test { private Map<String, Object> info = new HashMap<String, Object>(); public Map<String, Object> getInfo() { return this.info; } } } 

在问题中运行yaml会产生:

 {build={artifact=${project.artifactId}, version=${project.version}, name=${project.name}, description=${project.description}}} 

有多种选项可以设置前缀,控制如何处理缺less的属性等。有关更多信息,请参阅javadoc 。

下面的解决scheme是@Andy Wilkinson的解决scheme的简写,除了它不必使用单独的类或@Bean注释的方法。

application.yml看起来像这样

 input: name: raja age: 12 somedata: abcd: 1 bcbd: 2 cdbd: 3 @Component @EnableConfigurationProperties @ConfigurationProperties(prefix = "input") class SomeComponent { @Value("${input.name}") private String name; @Value("${input.age}") private Integer age; private HashMap<String, Integer> somedata; public HashMap<String, Integer> getSomedata() { return somedata; } public void setSomedata(HashMap<String, Integer> somedata) { this.somedata = somedata; } } 

我们可以同时使用@Value注解和@ConfigurationProperties ,没有问题。 但getter和setter是重要的, @EnableConfigurationProperties必须有@ConfigurationProperties工作。

我从@Szymon Stepniak提供的groovy解决scheme中尝试了这个想法,认为这对某个人会有帮助。

我今天遇到同样的问题,但不幸的是Andy的解决scheme对我来说并不合适。 在Spring Boot 1.2.1.RELEASE中更容易,但是你必须注意一些事情。

这里是我的application.yml有趣的部分:

 oauth: providers: google: api: org.scribe.builder.api.Google2Api key: api_key secret: api_secret callback: http://callback.your.host/oauth/google 

providers地图只包含一个地图条目,我的目标是为其他OAuth提供商提供dynamicconfiguration。 我想将这个映射注入一个服务,该服务将根据这个yaml文件中提供的configuration来初始化服务。 我最初的实施是:

 @Service @ConfigurationProperties(prefix = 'oauth') class OAuth2ProvidersService implements InitializingBean { private Map<String, Map<String, String>> providers = [:] @Override void afterPropertiesSet() throws Exception { initialize() } private void initialize() { //.... } } 

在启动应用程序后, OAuth2ProvidersService中的providers映射未初始化。 我尝试了Andy提出的解决scheme,但是并没有奏效。 我在该应用程序中使用Groovy ,所以我决定删除private并让Groovy生成getter和setter。 所以我的代码看起来像这样:

 @Service @ConfigurationProperties(prefix = 'oauth') class OAuth2ProvidersService implements InitializingBean { Map<String, Map<String, String>> providers = [:] @Override void afterPropertiesSet() throws Exception { initialize() } private void initialize() { //.... } } 

在那之后,一切都变好了。

虽然有一件事值得一提。 在我使它工作之后,我决定把这个字段设置为private并在setter方法中为setter提供直接的参数types。 不幸的是,它不会工作。 它会导致带有消息的org.springframework.beans.NotWritablePropertyException

 Invalid property 'providers[google]' of bean class [com.zinvoice.user.service.OAuth2ProvidersService]: Cannot access indexed value in property referenced in indexed property path 'providers[google]'; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'providers[google]' of bean class [com.zinvoice.user.service.OAuth2ProvidersService]: Bean property 'providers[google]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? 

请记住,如果您在Spring Boot应用程序中使用Groovy。

 foo.bars.one.counter=1 foo.bars.one.active=false foo.bars[two].id=IdOfBarWithKeyTwo public class Foo { private Map<String, Bar> bars = new HashMap<>(); public Map<String, Bar> getBars() { .... } } 

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding