簡體   English   中英

Spring了解YAML中的屬性

[英]Spring to understand properties in YAML

Spring是否放棄使用YAML作為.properties / .xml的替代品,因為:

[春天開發者]: ... YAML被認為是,但我們認為計算空白顯着是制作中的支持噩夢... [來自春季論壇的參考]

我很自信YAML對於屬性很有意義,我目前正在使用它,但是很難將屬性注入到

<property name="productName" value="${client.product.name}" />

時尚。

我缺少什么,或者我應該創建一個自定義的YamlPropertyPlaceholderConfigurer?

我不知道這有點太晚但不是 - 你不必實現整個YamlPropertyPlaceholderConfigurer而只需創建自定義PropertiesPersister並將其添加為可選參數。

這是您的配置的外觀

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <value>file:///C:/somewhere/site.yaml</value>
    </property>
    <property name="propertiesPersister" ref="persister"></property>
</bean>
<bean id="persister" class="com.foo.utils.YamlPropertiesPersister"></bean>

這里是使用SnakeYaml的裸骨(只讀)實現,隨意添加您需要的內容,包括錯誤處理

public class YamlPropertiesPersister implements PropertiesPersister {
@Override
public void load(Properties props, InputStream is) throws IOException {
    load(props, new InputStreamReader(is));
}

/**
 * We want to traverse map representing Yaml object and each time we find String=String pair we want to
 * save it as Property. As we are going deeper into map we generate compound key as path-like String
 * 
 * @param props
 * @param reader
 * @throws IOException
 * @see org.springframework.util.PropertiesPersister#load(java.util.Properties, java.io.Reader)
 */
@Override
public void load(Properties props, Reader reader) throws IOException {
    Yaml yaml = CollectorUtils.instanceOfYaml();
    Map<String, Object> map = (Map<String, Object>) yaml.load(reader);
    // now we can populate supplied props
    assignProperties(props, map, null);
}

/**
 * @param props
 * @param map
 */
public void assignProperties(Properties props, Map<String, Object> map, String path) {
    for (Entry<String, Object> entry : map.entrySet()) {
        String key = entry.getKey();
        if (StringUtils.isNotEmpty(path))
            key = path + "." + key;
        Object val = entry.getValue();
        if (val instanceof String) {
            // see if we need to create a compound key
            props.put(key, val);
        } else if (val instanceof Map) {
            assignProperties(props, (Map<String, Object>) val, key);
        }
    }
}

@Override
public void store(Properties props, OutputStream os, String header) throws IOException {
    throw new NotImplementedException("Current implementation is a read-only");
}

@Override
public void store(Properties props, Writer writer, String header) throws IOException {
    throw new NotImplementedException("Current implementation is a read-only");
}

@Override
public void loadFromXml(Properties props, InputStream is) throws IOException {
    throw new NotImplementedException("Use DefaultPropertiesPersister if you want to read/write XML");
}

@Override
public void storeToXml(Properties props, OutputStream os, String header) throws IOException {
    throw new NotImplementedException("Use DefaultPropertiesPersister if you want to load/store to XML");
}

@Override
public void storeToXml(Properties props, OutputStream os, String header, String encoding) throws IOException {
    throw new NotImplementedException("Use DefaultPropertiesPersister if you want to read/write XML");
}
}

作為額外的好處 - 這是我如何創建Yaml實例

    public static Yaml instanceOfYaml() {
    DumperOptions options = new DumperOptions();
    options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
    options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
    final Yaml yaml = new Yaml(new Loader(), new Dumper(options), new Resolver() {
        /**
         * @see org.yaml.snakeyaml.resolver.Resolver#addImplicitResolvers()
         */
        @Override
        protected void addImplicitResolvers() {
            addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
            // disable resolving of floats and integers
            // addImplicitResolver(Tags.FLOAT, FLOAT, "-+0123456789.");
            // addImplicitResolver(Tag.INT, INT, "-+0123456789");
            addImplicitResolver(Tag.MERGE, MERGE, "<");
            addImplicitResolver(Tag.NULL, NULL, "~nN\0");
            addImplicitResolver(Tag.NULL, EMPTY, null);
            addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
            addImplicitResolver(Tag.VALUE, VALUE, "=");
        }
    });
    return yaml;
}

您也可以在我的博客中閱讀此內容

對於使用Spring 3.1的用戶,可以注冊Yaml PropetySource。 SnakeYaml代碼來自Bostone代碼(感謝),適用於Spring 3.1的新PropertySource系統。

import com.google.common.base.Preconditions;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Dumper;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
import org.yaml.snakeyaml.Loader;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.resolver.Resolver;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

/**
 * @author Sebastien Lorber <i>(lorber.sebastien@gmail.com)</i>
 */
public class YamlPropertiesSource extends PropertiesPropertySource {


  public YamlPropertiesSource(String name, Resource yamlResource) {
    super(name, getPropertySource(yamlResource) );
  }

  private static Properties getPropertySource(Resource yamlResource) {
    Preconditions.checkArgument(yamlResource != null,"no yaml resource provided");
    try {
      InputStream is = yamlResource.getInputStream();
      Properties properties = new Properties();
      load(properties, is);
      return properties;
    } catch ( Exception e ) {
      throw new IllegalStateException("Can't get PropertySource from YAML resource=" + yamlResource,e);
    }
  }

  private static void load(Properties props, InputStream is) throws IOException {
    load(props, new InputStreamReader(is));
  }

  private static void load(Properties props, Reader reader) throws IOException {
    Yaml yaml = instanceOfYaml();
    @SuppressWarnings("unchecked")
    Map<String, Object> map = (Map<String, Object>) yaml.load(reader);
    // now we can populate supplied props
    assignProperties(props, map, null);
  }

  private static void assignProperties(Properties props, Map<String, Object> map, String path) {
    for (Entry<String, Object> entry : map.entrySet()) {
      String key = entry.getKey();
      if ( StringUtils.hasLength(path) )
        key = path + "." + key;
      Object val = entry.getValue();
      if (val instanceof String) {
        // see if we need to create a compound key
        props.put(key, val);
      } else if (val instanceof Map) {
        assignProperties(props, (Map<String, Object>) val, key);
      }
    }
  }

  public static Yaml instanceOfYaml() {
    DumperOptions options = new DumperOptions();
    options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
    options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
    final Yaml yaml = new Yaml(new Loader(), new Dumper(options), new Resolver() {
      /**
       * @see org.yaml.snakeyaml.resolver.Resolver#addImplicitResolvers()
       */
      @Override
      protected void addImplicitResolvers() {
        addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
        // disable resolving of floats and integers
        // addImplicitResolver(Tags.FLOAT, FLOAT, "-+0123456789.");
        // addImplicitResolver(Tag.INT, INT, "-+0123456789");
        addImplicitResolver(Tag.MERGE, MERGE, "<");
        addImplicitResolver(Tag.NULL, NULL, "~nN\0");
        addImplicitResolver(Tag.NULL, EMPTY, null);
        addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
        addImplicitResolver(Tag.VALUE, VALUE, "=");
      }
    });
    return yaml;
  }

}

請注意,這也受ResourcePropertySource的啟發,並在ISO 8859-1 charset中加載屬性。 我為此開了一個錯誤: SPR-10096

您可以將此屬性源添加到應用程序上下文中。 這也可以在您的單元測試中完成:

public class PropertySourceContextLoader extends GenericXmlContextLoader {
    @Override
    protected void loadBeanDefinitions(GenericApplicationContext context,MergedContextConfiguration mergedConfig) {
        PropertySource<String> ps = new MyPropertySource();
        context.getEnvironment().getPropertySources().addLast(ps);
        super.loadBeanDefinitions(context, mergedConfig);
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = PropertySourceContextLoader.class, locations = { "classpath:/spring-application-context.xml" })
public class SpringBasedTest {
         ..........
}

對於像我這樣完全和完全沒有知道作者實際在做什么,但無論如何都需要這樣做的完整和完整的小塊......這就是我如何使它發揮作用。 但是不知道如何降級instanceOfYaml()。 另外一件事,我的Spring Boot Eclipse項目從標記為.yml的文件中讀取,而不是.yaml

import org.springframework.util.PropertiesPersister;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Dumper;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
import org.yaml.snakeyaml.Loader;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.resolver.Resolver;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

public class YamlPropertiesPersister implements PropertiesPersister {
    @Override
    public void load(Properties props, InputStream is) throws IOException {
        load(props, new InputStreamReader(is));
    }

    /**
     * We want to traverse map representing Yaml object and each time we will find String:String value pair we want to
     * save it as Property. As we are going deeper into map we generate a compound key as path-like String
     *
     * @param props
     * @param reader
     * @throws IOException
     * @see org.springframework.util.PropertiesPersister#load(java.util.Properties, java.io.Reader)
     */
    @Override
    public void load(Properties props, Reader reader) throws IOException {
        Yaml yaml = instanceOfYaml();
        Map<String, Object> map = (Map<String, Object>) yaml.load(reader);
        // now we can populate supplied props
        assignProperties(props, map, null);
    }

    /**
     * @param props
     * @param map
     */
    public void assignProperties(Properties props, Map<String, Object> map, String path) {
        for (Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            if (!StringUtils.isEmpty(path))
                key = path + "." + key;
            Object val = entry.getValue();
            if (val instanceof String) {
                // see if we need to create a compound key
                props.put(key, val);
            } else if (val instanceof Map) {
                assignProperties(props, (Map<String, Object>) val, key);
            }
        }
    }

    @Override
    public void store(Properties props, OutputStream os, String header) throws IOException {
        throw new UnsupportedOperationException("Current implementation is a read-only");
    }

    @Override
    public void store(Properties props, Writer writer, String header) throws IOException {
        throw new UnsupportedOperationException("Current implementation is a read-only");
    }

    @Override
    public void loadFromXml(Properties props, InputStream is) throws IOException {
        throw new UnsupportedOperationException("Use DefaultPropertiesPersister if you want to read/write XML");
    }

    @Override
    public void storeToXml(Properties props, OutputStream os, String header) throws IOException {
        throw new UnsupportedOperationException("Use DefaultPropertiesPersister if you want to load/store to XML");
    }

    @Override
    public void storeToXml(Properties props, OutputStream os, String header, String encoding) throws IOException {
        throw new UnsupportedOperationException("Use DefaultPropertiesPersister if you want to read/write XML");
    }


    public static Yaml instanceOfYaml() {
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        options.setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED);
        final Yaml yaml = new Yaml(new Loader(), new Dumper(options), new Resolver() {
            /**
             * @see org.yaml.snakeyaml.resolver.Resolver#addImplicitResolvers()
             */
            @Override
            protected void addImplicitResolvers() {
                addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
                // disable resolving of floats and integers
                // addImplicitResolver(Tags.FLOAT, FLOAT, "-+0123456789.");
                // addImplicitResolver(Tag.INT, INT, "-+0123456789");
                addImplicitResolver(Tag.MERGE, MERGE, "<");
                addImplicitResolver(Tag.NULL, NULL, "~nN\0");
                addImplicitResolver(Tag.NULL, EMPTY, null);
                addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
                addImplicitResolver(Tag.VALUE, VALUE, "=");
            }
        });
        return yaml;
    }
}

您引用的論壇帖子來自dmServer論壇,而不是Spring Framework,兩者之間的關系很少,所以我不會讀到任何內容。

最重要的是,YAML在Java世界中幾乎聞所未聞,因此添加對它的支持本來就是一個象征性的手勢(如果你原諒這個表達式)。 XML在Java中占主導地位,特別是在服務器端,因此在游泳潮流中幾乎沒有什么用處,特別是像YAML這樣的少數格式。

話雖如此,編寫自己的YamlPropertyPlaceholderConfigurer應該很容易,假設您可以找到Java的YAML解析器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM