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