Могу ли я вручную загрузить @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);
}
}