【问题标题】:Is there a way to read property file from inside BeanFactoryPostProcessor?有没有办法从 BeanFactoryPostProcessor 中读取属性文件?
【发布时间】:2021-04-09 07:34:28
【问题描述】:

我正在使用BeanFactoryPostProcessor 在运行时创建 Rest Templates bean。其余模板的配置放在一个 yml 文件中。

config:
  banks:
    A1:
      restTemplate:
        connectTimeout: 16000
        socketTimeout: 18000
        maxPerRoute: 10
        maxTotalConnection: 20
    B1:
      restTemplate:
        connectTimeout: 20000
        socketTimeout: 20000
        maxPerRoute: 10
        maxTotalConnection: 2

A1、B1 是动态的。属性文件可能有 C1、D1 等。我实现了EnvironmentAware .但它只能获得类似的属性

environment.getProperty("config.banks.A1.restTemplate.connectTimeout");

有没有办法以 dto 的形式获取这些动态属性,类似于使用@ConfiguratioProperties

我什至尝试了以下方法:

 @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new FileSystemResource(environment.resolvePlaceholders("${catalina.home}") + "/conf/restTemplate_prop.yml"));
        bean.afterPropertiesSet();

        Properties props = bean.getObject();
        Enumeration names = props.propertyNames();

        while (names.hasMoreElements()) {
            String name = names.nextElement().toString();
            String value = props.getProperty(name);
}

但我得到的属性为:

我什至没有得到所有的属性。有没有办法在 dto 中获取属性,有没有一种有效的方法来做到这一点? 注意:我目前使用的是 Spring Boot 1.5.2 版,所以我没有 Binder API。

【问题讨论】:

  • 不在 BeanFactoryPostProcessor 中,因为它在 Spring 或 Spring Boot 读取属性之前执行。因此,您需要手动加载并绑定到 DTO。同样尝试使用 PropertiesLoader 加载 YAML 文件显然不起作用,它不是属性文件而是 YAML 文件。如果有什么需要 YamlPropertiesFactoryBean 加载并将其解析为 Properties 对象。

标签: spring spring-boot


【解决方案1】:
@Component
@ConfigurationProperties(prefix = "config.banks.restTemplate")
public class ApplicationProps {
    
    
    private List<Map<String, Object>> props;
    private List<RestTemplateConfiguration> restTemplateConfigurations;
    
    // getters and setters

    public static class RestTemplateConfiguration {

        private String name;
        private Integer connectTimeout;
        private Integer socketTimeout;
        private Integer maxPerRoute;
        private Integer maxTotalConnection

        // getters and setters

    }
}

然后让你的 yaml 包含一个复杂属性的列表

config:
  banks:
      restTemplate:
        -
          name: A1
          connectTimeout: 16000
          socketTimeout: 18000
          maxPerRoute: 10
          maxTotalConnection: 20
      
        - 
          name: B1
          connectTimeout: 20000
          socketTimeout: 20000
          maxPerRoute: 10
          maxTotalConnection: 2

然后在应用程序启动后,您可以AutowireApplicationProps 并从restTemplateConfigurations 列表中检索您喜欢的任何内容。

【讨论】:

  • 我做不到。其余的 Template 需要由 Spring 的 IOC 容器管理。
  • @MohendraAmatya 站不住脚。它要么是您拥有一组配置属性的单例,要么是您手动初始化的多个 restTemplate 实例,并在手动选择要使用的实例
【解决方案2】:

感谢第一条评论,我找到了一种读取和操作属性文件的方法。 我使用了YamlPropertiesFactoryBean API。

YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new FileSystemResource(environment.resolvePlaceholders("${catalina.home}") + "/conf/rest_prop.yml"));
        yaml.setResolutionMethod(YamlProcessor.ResolutionMethod.OVERRIDE);
        yaml.afterPropertiesSet();
        Map<Object, Object> yamlProperties = yaml.getObject();

现在我只修改 yamlProperties 映射。 地图是这样制作的:

config.banks.A1.restTemplate.connectTimeout -> 16000
config.banks.A1.restTemplate.maxPerRoute -> 10
config.banks.A1.restTemplate.maxTotalConnection -> 20
config.banks.A1.restTemplate.socketTimeout -> 18000
config.banks.B1.restTemplate.connectTimeout -> 20000
config.banks.B1.restTemplate.maxPerRoute -> 10
config.banks.B1.restTemplate.maxTotalConnection -> 2
config.banks.B1.restTemplate.socketTimeout -> 20000

那么这个地图就可以转换成我选择的对象了。

【讨论】:

    猜你喜欢
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 2019-06-29
    • 2020-08-24
    • 2018-06-10
    • 2012-06-22
    相关资源
    最近更新 更多