Подтвердить что ты не робот

Spring Загрузка - введите карту из application.yml

У меня есть приложение Spring Boot со следующим 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.

4b9b3361

Ответ 1

Вы можете ввести карту с помощью @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.

Ответ 2

Ниже решение является сокращением для решения @Andy Wilkinson, за исключением того, что ему не нужно использовать отдельный класс или аннотированный метод @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, без проблем. Но геттеры и сеттеры важны, и @EnableConfigurationProperties должен иметь @ConfigurationProperties для работы.

Я пробовал эту идею из решения groovy, предоставленного @Szymon Stepniak, подумал, что это будет полезно для кого-то.

Ответ 3

Сегодня я столкнулся с той же проблемой, но, к сожалению, решение для 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 map в 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() {
       //....
    }
}

После этого небольшое изменение все сработало.

Хотя есть одна вещь, о которой стоит упомянуть. После того, как я сделаю это, я решил сделать это поле 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?

Имейте это в виду, если вы используете Groovy в своем приложении для загрузки Spring.