2017-07-24 144 views
0

我的用例有点古怪,但基本上,我想读取yaml文件的一部分并将其映射到适用于Spring应用程序的java对象。这是一个在春天很常见和平凡的操作(只需使用@ConfigurationProperties)。用前缀读取合格的yaml文件,而不使用注释或xml

然而,就我而言,我希望在生命周期的早些时候完成这个读取,即在BeanFactoryPostProcessor挂接的时候 - 以便使用yml中指定的指令来动态创建一些bean。

我能得到这个工作与application.properties但与application.yml

我希望在阳明海运到POJO的顺序杠杆映射部分使用阳明也利用分层映射文件和数据结构(名单,地图等)。

下面是如何读取application.properties的示例。 https://blog.pchudzik.com/201705/dynamic-beans/

我在https://github.com/balamuru/yaml-loader上设置了一个简单的框架项目来尝试不同的技术。 任何想法?

@Component 
@EnableConfigurationProperties(SampleDataConfig.class) 
class ConfigurableBeanFactory implements BeanFactoryPostProcessor, InitializingBean { 
    private List<String> beanInstances = new ArrayList<>(); 

    @Override 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 
     final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; 

     Map<String, SampleDataConfig> beans = beanFactory.getBeansOfType(SampleDataConfig.class); 
     System.err.println(""); 

     beanInstances.forEach(instance -> { 
      registry.registerBeanDefinition(instance, BeanDefinitionBuilder 
        .rootBeanDefinition(SampleDataConfig.class) 
        .addConstructorArgValue(instance) 
        .getBeanDefinition()); 
     }); 
    } 

    @Override 
    public void afterPropertiesSet() throws Exception { 
//  this.beanInstances = asList(PropertiesLoaderUtils 
//    .loadProperties(new ClassPathResource("/application.properties")) 
//    .getProperty("dynamic-beans.instances", "") 
//    .split(",")); 

     /** 
     * Rather than reading from application.properties, 
     * I would like to be able to load up the relevant prefix qualified segments (com.foo.bar.stuff) mapping to my POJO (SampleDataConfig,class) 
     * loaded from application.yml 
     */ 
    } 

} 

在内部,Spring使用下面的机制,但我希望有利用这种不重新发明了春天:)

public class ConfigurationPropertiesBindingPostProcessor ...{ 
. 
. 

    private void postProcessBeforeInitialization(Object bean, String beanName, 
      ConfigurationProperties annotation) { 
     Object target = bean; 
     PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
       target); 
     factory.setPropertySources(this.propertySources); 
     factory.setValidator(determineValidator(bean)); 
     // If no explicit conversion service is provided we add one so that (at least) 
     // comma-separated arrays of convertibles can be bound automatically 
     factory.setConversionService(this.conversionService == null 
       ? getDefaultConversionService() : this.conversionService); 
     if (annotation != null) { 
      factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields()); 
      factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields()); 
      factory.setExceptionIfInvalid(annotation.exceptionIfInvalid()); 
      factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties()); 
      if (StringUtils.hasLength(annotation.prefix())) { 
       factory.setTargetName(annotation.prefix()); //====> use annotation prefix 
      } 
     } 
     try { 
      factory.bindPropertiesToTarget(); //===> bind properties 
     } 

感谢一个更简单的方法

回答

-1
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean(); 
yaml.setResources(new ClassPathResource("application.yml")); 
configProperty = yaml.getObject(); 
Set<Object> keys = configProperty.keySet(); 

以下是我的YAML配置,它看起来像:

template: 
    config: 
    broker-urls: 
    - tcp://127.0.0.1:61616 
    - tcp://127.0.0.1:61617 
    - tcp://127.0.0.1:61618 
    qeues: 
    - Test 
    - Demo 
    - Qeue3 

应用上述代码后,您将获得如下所示的转换属性:

template.config.broker-urls[0]=tcp://127.0.0.1:61616 
template.config.broker-urls[1]=tcp://127.0.0.1:61617 
template.config.broker-urls[1]=tcp://127.0.0.1:61618 

template.config.qeues[0]=Test 
template.config.qeues[1]=Demo 
template.config.qeues[1]=Qeue3