[java] Spring Boot-application.yml에서 맵 삽입

나는이 봄 부트 다음에 응용 프로그램 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}}}

접두사 설정, 누락 된 속성 처리 방법 제어 등에 대한 다양한 옵션이 있습니다. 자세한 내용은 javadoc 을 참조하십시오.


답변

아래 솔루션은 @Andy Wilkinson의 솔루션에 대한 속기입니다. 단, 별도의 클래스 나 @Bean주석이 달린 메서드 를 사용할 필요가 없습니다 .

application.yml :

input:
  name: raja
  age: 12
  somedata:
    abcd: 1 
    bcbd: 2
    cdbd: 3

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;
    }

}

우리는 @Value주석과 @ConfigurationProperties문제를 모두 클럽화할 수 있습니다. 그러나 게터와 세터는 중요하며 작동 @EnableConfigurationProperties해야합니다 @ConfigurationProperties.

@Szymon Stepniak에서 제공 한 멋진 솔루션에서이 아이디어를 시도했는데 누군가에게 유용 할 것이라고 생각했습니다.


답변

오늘도 같은 문제가 발생했지만 안타깝게도 Andy의 솔루션이 작동하지 않았습니다. 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 공급자에 대한 동적 구성을 제공하는 것입니다. 이 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() {
       //....
    }
}

응용 프로그램을 시작한 후 providers맵 인 OAuth2ProvidersService이 초기화되지 않았습니다. Andy가 제안한 솔루션을 시도했지만 제대로 작동하지 않았습니다. 나는 그 응용 프로그램에서 Groovy 를 사용 하기 때문에 privateGroovy가 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() {
       //....
    }
}

그 작은 변화 후에 모든 것이 작동했습니다.

언급 할 가치가있는 한 가지가 있습니다. 내가 작동하게 한 후에 나는이 필드를 만들고 privatesetter 메서드에서 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?

Spring Boot 애플리케이션에서 Groovy를 사용하는 경우이를 염두에 두십시오.


답변

구성에서 맵을 검색하려면 구성 클래스가 필요합니다. 불행히도 @Value 주석은 트릭을 수행하지 않습니다.

Application.yml

entries:
  map:
     key1: value1
     key2: value2

구성 클래스 :

@Configuration
@ConfigurationProperties("entries")
@Getter
@Setter
 public static class MyConfig {
     private Map<String, String> map;
 }


답변

당기위한 솔루션 사용 @Value을 에서 application.yml 속성으로 코딩 여러

application.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 

여기서 맵 속성 “my-map-property-name”의 값은 문자열 내부 에 JSON 형식으로 저장되며 줄 끝에 \ 를 사용하여 여러 줄을 달성했습니다.

myJavaClass.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...
    } }

}

더 많은 설명

  • \ yaml에서 문자열을 여러 줄로 나누는 데 사용됩니다.

  • \ “ 는 yaml 문자열의”(따옴표)에 대한 이스케이프 문자입니다.

  • @Value에 의해 Map으로 변환 될 yaml의 {key : value} JSON

  • # {} SpEL 표현이며 @Value에서 json int Map 또는 Array / list Reference 를 변환하는 데 사용할 수 있습니다.

스프링 부트 프로젝트에서 테스트 됨


답변

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


답변

추가 구조를 피하려면 더 간단하게 만들 수 있습니다.

service:
  mappings:
    key1: value1
    key2: value2
@Configuration
@EnableConfigurationProperties
public class ServiceConfigurationProperties {

  @Bean
  @ConfigurationProperties(prefix = "service.mappings")
  public Map<String, String> serviceMappings() {
    return new HashMap<>();
  }

}

그런 다음 예를 들어 생성자와 함께 평소와 같이 사용하십시오.

public class Foo {

  private final Map<String, String> serviceMappings;

  public Foo(Map<String, String> serviceMappings) {
    this.serviceMappings = serviceMappings;
  }

}