[英]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.