Могу ли я вручную загрузить @ConfigurationProperties без Spring AppContext?

есть ли способ загрузить класс, помеченный @ConfigurationProperties без использования контекста Spring напрямую? В основном я хочу повторно использовать всю интеллектуальную логику, которую Spring делает, но для компонента, который я вручную создаю вне жизненного цикла Spring.

у меня есть боб, который счастливо загружается весной (Boot), и я могу ввести это в мои другие служебные бобы:

@ConfigurationProperties(prefix="my")
public class MySettings {
    String property1;
    File property2;
} 

посмотреть весна -- это подробнее http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-command-line-args

но теперь мне нужно получить доступ к этому Бобу из класса, который создается вне Spring (Hibernate). Класс создается так рано в процессе запуска приложения, что Spring Boot еще не сделал контекст приложения доступным с помощью классических вспомогательных методов поиска или статических ссылок roll-my-own.

поэтому я вместо этого хочу сделайте что-нибудь вроде:

MySettings mySettings = new MySettings(); 
SpringPropertyLoadingMagicClass loader = new SpringPropertyLoadingMagicClass();
loader.populatePropertyValues(mySettings);

и у MySettings в конечном итоге все его значения загружаются из командной строки, системных свойств, приложения.свойства и т. д. Есть ли какой-то класс весной, который делает что-то подобное, или все это слишком переплетено с контекстом приложения?

очевидно, я мог бы просто загрузить файл свойств сам, но я действительно хочу сохранить логику Spring Boot вокруг использования переменных командной строки (например, --my.property1=xxx), или системные переменные, или приложение.свойства или даже файл yaml, а также его логика вокруг расслабленной привязки и преобразования типов (например, property2-это файл), так что все это работает точно так же, как при использовании в контексте Spring.

возможно или мечта?

Спасибо за вашу помощь!

2 ответов


класс "magic", который вы ищете, это PropertiesConfigurationFactory. Но я бы поставил под сомнение вашу потребность в этом - если вам нужно только связать один раз, то весна должна быть в состоянии сделать это за вас, и если у вас есть проблемы с жизненным циклом, было бы лучше обратиться к ним (в случае, если они сломают что-то еще).


у меня была такая же "проблема". Вот как я решил это в SpringBoot версии 1.3.xxx и 1.4.1.

предположим, у нас есть следующий файл конфигурации yaml:

foo:
  apis:
      -
       name: Happy Api
       path: /happyApi.json?v=bar
      -
       name: Grumpy Api
       path: /grumpyApi.json?v=grrr

и у нас есть следующие ConfigurationProperties:

@ConfigurationProperties(prefix = "foo")
public class ApisProperties {
    private List<ApiPath> apis = Lists.newArrayList();

    public ApisProperties() {
    }

    public List<ApiPath> getApis() {
        return apis;
    }

    public static class ApiPath {
        private String name;
        private String path;

        public String getName() {
            return name;
        }

        public void setName(final String aName) {
            name = aName;
        }

        public String getPath() {
            return path;
        }

        public void setPath(final String aPath) {
            path = aPath;
        }
    }
} 

затем, чтобы сделать "волшебные" вещи Spring Boot программно (например, загрузка некоторых свойств в статическом методе), вы можете сделать:

private static ApisProperties apiProperties() {
    try {
        ClassPathResource resource;
        resource = new ClassPathResource("/config/application.yml");

        YamlPropertiesFactoryBean factoryBean;
        factoryBean = new YamlPropertiesFactoryBean();
        factoryBean.setSingleton(true); // optional depends on your use-case
        factoryBean.setResources(resource);

        Properties properties;
        properties = factoryBean.getObject();

        MutablePropertySources propertySources;
        propertySources = new MutablePropertySources();
        propertySources.addLast(new PropertiesPropertySource("apis", properties));

        ApisProperties apisProperties;
        apisProperties = new ApisProperties();

        PropertiesConfigurationFactory<ApisProperties> configurationFactory;
        configurationFactory = new PropertiesConfigurationFactory<>(apisProperties);
        configurationFactory.setPropertySources(propertySources);
        configurationFactory.setTargetName("foo"); // it's the same prefix as the one defined in the @ConfigurationProperties

        configurationFactory.bindPropertiesToTarget();
        return apisProperties; // apiProperties are fed with the values defined in the application.yaml

    } catch (BindException e) {
        throw new IllegalArgumentException(e);

    }
}