Java Spring Boot - 从 application.yml 注入地图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24917194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Boot - inject map from application.yml
提问by levant pied
I have a Spring Bootapplication with the following application.yml
- taken basically from here:
我有一个带有以下内容的Spring Boot应用程序application.yml
- 基本上取自这里:
info:
build:
artifact: ${project.artifactId}
name: ${project.name}
description: ${project.description}
version: ${project.version}
I can inject particular values, e.g.
我可以注入特定的值,例如
@Value("${info.build.artifact}") String value
I would like, however, to inject the whole map, i.e. something like this:
但是,我想注入整个地图,即像这样:
@Value("${info}") Map<String, Object> info
Is that (or something similar) possible? Obviously, I can load yaml directly, but was wondering if there's something already supported by Spring.
那(或类似的东西)可能吗?显然,我可以直接加载 yaml,但想知道 Spring 是否已经支持某些内容。
采纳答案by Andy Wilkinson
You can have a map injected using @ConfigurationProperties
:
您可以使用@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;
}
}
}
Running this with the yaml in the question produces:
使用问题中的 yaml 运行它会产生:
{build={artifact=${project.artifactId}, version=${project.version}, name=${project.name}, description=${project.description}}}
There are various options for setting a prefix, controlling how missing properties are handled, etc. See the javadocfor more information.
有多种选项可用于设置前缀、控制缺失属性的处理方式等。有关更多信息,请参阅javadoc。
回答by Szymon Stepniak
I run into the same problem today, but unfortunately Andy's solution didn't work for me. In Spring Boot 1.2.1.RELEASE it's even easier, but you have to be aware of a few things.
我今天遇到了同样的问题,但不幸的是安迪的解决方案对我不起作用。在 Spring Boot 1.2.1.RELEASE 中它更容易,但你必须注意一些事情。
Here is the interesting part from my application.yml
:
这是我的有趣部分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
map contains only one map entry, my goal is to provide dynamic configuration for other OAuth providers. I want to inject this map into a service that will initialize services based on the configuration provided in this yaml file. My initial implementation was:
providers
map 只包含一个 map 条目,我的目标是为其他 OAuth 提供者提供动态配置。我想将此映射注入一个服务,该服务将根据此 yaml 文件中提供的配置初始化服务。我最初的实现是:
@Service
@ConfigurationProperties(prefix = 'oauth')
class OAuth2ProvidersService implements InitializingBean {
private Map<String, Map<String, String>> providers = [:]
@Override
void afterPropertiesSet() throws Exception {
initialize()
}
private void initialize() {
//....
}
}
After starting the application, providers
map in OAuth2ProvidersService
was not initialized. I tried the solution suggested by Andy, but it didn't work as well. I use Groovyin that application, so I decided to remove private
and let Groovy generates getter and setter. So my code looked like this:
启动应用程序后,未初始化providers
map in OAuth2ProvidersService
。我尝试了安迪建议的解决方案,但效果不佳。我在那个应用程序中使用了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() {
//....
}
}
After that small change everything worked.
在那次小的改变之后,一切都奏效了。
Although there is one thing that might be worth mentioning. After I make it working I decided to make this field private
and provide setter with straight argument type in the setter method. Unfortunately it wont work that. It causes org.springframework.beans.NotWritablePropertyException
with message:
尽管有一件事可能值得一提。在我让它工作后,我决定创建这个字段private
并在 setter 方法中为 setter 提供直接参数类型。不幸的是它不会工作。它导致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?
Keep it in mind if you're using Groovy in your Spring Boot application.
如果您在 Spring Boot 应用程序中使用 Groovy,请记住这一点。
回答by raksja
Below solution is a shorthand for @Andy Wilkinson's solution, except that it doesn't have to use a separate class or on a @Bean
annotated method.
下面的解决方案是@Andy Wilkinson 解决方案的简写,只是它不必使用单独的类或带@Bean
注释的方法。
application.yml:
应用程序.yml:
input:
name: raja
age: 12
somedata:
abcd: 1
bcbd: 2
cdbd: 3
SomeComponent.java:
SomeComponent.java:
@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;
}
}
We can club both @Value
annotation and @ConfigurationProperties
, no issues. But getters and setters are important and @EnableConfigurationProperties
is must to have the @ConfigurationProperties
to work.
我们可以同时使用@Value
注释和@ConfigurationProperties
,没有问题。但是 getter 和 setter 很重要,@EnableConfigurationProperties
必须使用它们@ConfigurationProperties
。
I tried this idea from groovy solution provided by @Szymon Stepniak, thought it will be useful for someone.
我从@Szymon Stepniak 提供的 groovy 解决方案中尝试了这个想法,认为它对某人有用。
回答by emerson moura
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
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding
回答by Orbite
To retrieve map from configuration you will need configuration class. @Value annotation won't do the trick, unfortunately.
要从配置中检索地图,您将需要配置类。不幸的是,@Value 注释不起作用。
Application.yml
应用程序.yml
entries:
map:
key1: value1
key2: value2
Configuration class:
配置类:
@Component
@ConfigurationProperties("entries")
@Getter
@Setter
public static class MyConfig {
private Map<String, String> map;
}
回答by Milan
Solution for pulling Mapusing @Valuefrom application.ymlproperty coded as multiline
使用@Value从 application.yml属性中提取Map 的解决方案编码为多行
application.yml
应用程序.yml
other-prop: just for demo
my-map-property-name: "{\
key1: \"ANY String Value here\", \
key2: \"any number of items\" , \
key3: \"Note the Last item does not have comma\" \
}"
other-prop2: just for demo 2
Here the value for our map property "my-map-property-name" is stored in JSONformat inside a stringand we have achived multiline using \at end of line
这里,我们的地图属性“my-map-property-name”的值以JSON格式存储在一个字符串中,我们在行尾使用\ 实现了多行
myJavaClass.java
我的JavaClass.java
import org.springframework.beans.factory.annotation.Value;
public class myJavaClass {
@Value("#{${my-map-property-name}}")
private Map<String,String> myMap;
public void someRandomMethod (){
if(myMap.containsKey("key1")) {
//todo...
} }
}
More explanation
更多解释
\in yaml it is Used to break string into multiline
\"is escape charater for "(quote) in yaml string
{key:value}JSON in yaml which will be converted to Map by @Value
#{ }it is SpEL expresion and can be used in @Value to convert json int Map or Array / list Reference
\在 yaml 中用于将字符串分成多行
\"是 yaml 字符串中 "(quote) 的转义字符
yaml 中的{key:value}JSON 将被 @Value 转换为 Map
#{ }是SpEL 表达式,可以在@Value 中使用,转换json int Map 或Array / list参考
Tested in a spring boot project
在 Spring Boot 项目中测试