我可以在没有Spring AppContext的情况下手动加载@ConfigurationProperties吗?

zon*_*ski 8 java spring spring-boot

有没有办法直接加载标有的类@ConfigurationProperties而不使用Spring Context?基本上我想重用Spring所有的智能逻辑,但对于我在Spring生命周期之外手动实例化的bean.

我有一个在Spring(Boot)中快乐加载的bean,我可以将它注入我的其他Service bean:

@ConfigurationProperties(prefix="my")
public class MySettings {
    String property1;
    File property2;
} 
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅spring docco http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-command-line-args

但是现在我需要从Spring(在Hibernate之外)创建的类中访问这个bean.该类是在应用程序启动过程的早期创建的,Spring Boot尚未通过经典查找帮助器方法或自己动态的静态引用使应用程序上下文可用.

所以我反而想做一些事情:

MySettings mySettings = new MySettings(); 
SpringPropertyLoadingMagicClass loader = new SpringPropertyLoadingMagicClass();
loader.populatePropertyValues(mySettings);
Run Code Online (Sandbox Code Playgroud)

从命令行,系统属性,app.properties等开始,MySettings最终会加载它的所有值.在Spring中是否有类似这样的东西,或者它是否与应用程序上下文交织在一起?

显然我可以自己加载Properties文件,但我真的想保留Spring Boot的逻辑,使用命令行变量(例如--my.property1 = xxx),或系统变量,或者application.properties甚至是yaml文件,如以及它在松弛绑定和类型转换方面的逻辑(例如,property2是一个文件),因此它与Spring上下文中使用的完全相同.

可能还是梦想?

谢谢你的帮助!

ctr*_*uan 13

我遇到过同样的问题".以下是我在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
Run Code Online (Sandbox Code Playgroud)

我们有以下内容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;
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

然后,以编程方式执行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);

    }
}
Run Code Online (Sandbox Code Playgroud)


edg*_*aff 6

这是 ctranxuan 对 Spring Boot 2.x 的回答的更新。在我们的情况下,我们避免为单元测试启动 Spring 上下文,但确实喜欢测试我们的配置类(AppConfig在本例中被调用,其设置以 为前缀app):

public class AppConfigTest {
  private static AppConfig config;

  @BeforeClass
  public static void init() {
    YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
    factoryBean.setResources(new ClassPathResource("application.yaml"));

    Properties properties = factoryBean.getObject();

    ConfigurationPropertySource propertySource = new MapConfigurationPropertySource(properties);
    Binder binder = new Binder(propertySource);

    config = binder.bind("app", AppConfig.class).get(); // same prefix as @ConfigurationProperties
  }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*yer 5

你正在寻找的"神奇"课程是PropertiesConfigurationFactory.但是我会质疑你对它的需要 - 如果你只需要绑定一次,那么Spring应该能够为你做到这一点,如果你有生命周期问题,最好解决这些问题(万一它们会破坏别的东西).