由Typesafe配置支持的Spring环境
我想在我的项目中使用typesafe配置(HOCON配置文件),这有助于简化和组织应用程序配置。 目前我正在使用普通的Java属性文件(application.properties),这在大项目中很难处理。
我的项目是Spring MVC(不是Spring启动项目)。 有没有办法支持我的Spring环境(我将注入到我的服务中)以支持typesafe配置。 这不应该像@Value
注释,@ @Autowired Environment
等那样制止我现有的环境使用。
如何以最小的努力和我的代码更改来完成此操作。
这是我目前的解决方案:寻找还有其他更好的方法
@Configuration public class PropertyLoader{ private static Logger logger = LoggerFactory.getLogger(PropertyLoader.class); @Bean @Autowired public static PropertySourcesPlaceholderConfigurer properties(Environment env) { PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); Config conf = ConfigFactory.load(); conf.resolve(); TypesafePropertySource propertySource = new TypesafePropertySource("hoconSource", conf); ConfigurableEnvironment environment = (StandardEnvironment)env; MutablePropertySources propertySources = environment.getPropertySources(); propertySources.addLast(propertySource); pspc.setPropertySources(propertySources); return pspc; } } class TypesafePropertySource extends PropertySource{ public TypesafePropertySource(String name, Config source) { super(name, source); } @Override public Object getProperty(String name) { return this.getSource().getAnyRef(name); } }
我认为我提出了比手动将PropertySource
添加到属性源更加惯用的方法。 创建一个PropertySourceFactory
并使用@PropertySource
引用它
首先,我们有一个类似于你拥有的TypesafeConfigPropertySource
:
public class TypesafeConfigPropertySource extends PropertySource { public TypesafeConfigPropertySource(String name, Config source) { super(name, source); } @Override public Object getProperty(String path) { if (source.hasPath(path)) { return source.getAnyRef(path); } return null; } }
接下来,我们创建一个返回该属性源的PropertySource 工厂
public class TypesafePropertySourceFactory implements PropertySourceFactory { @Override public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException { Config config = ConfigFactory.load(resource.getResource().getFilename()).resolve(); String safeName = name == null ? "typeSafe" : name; return new TypesafeConfigPropertySource(safeName, config); } }
最后,在我们的配置文件中,我们可以像任何其他PropertySource
一样引用属性源,而不必自己添加PropertySource:
@Configuration @PropertySource(factory=TypesafePropertySourceFactory.class, value="someconfig.conf") public class PropertyLoader { // Nothing needed here }
你创建一个PropertySource类,如下所示,它与你的类似,区别在于你必须返回值或null并且不让lib抛出一个丢失的exception
public class TypesafeConfigPropertySource extends PropertySource { private static final Logger LOG = getLogger(TypesafeConfigPropertySource.class); public TypesafeConfigPropertySource(String name, Config source) { super(name, source); } @Override public Object getProperty(String name) { try { return source.getAnyRef(name); } catch (ConfigException.Missing missing) { LOG.trace("Property requested [{}] is not set", name); return null; } } }
第二步是按如下方式定义bean
@Bean public TypesafeConfigPropertySource provideTypesafeConfigPropertySource( ConfigurableEnvironment env) { Config conf = ConfigFactory.load().resolve(); TypesafeConfigPropertySource source = new TypesafeConfigPropertySource("typeSafe", conf); MutablePropertySources sources = env.getPropertySources(); sources.addFirst(source); // Choose if you want it first or last return source; }
如果您想要将属性自动assembly到其他bean,您需要使用注释@DependsOn
到propertysource bean,以确保它首次加载
希望能帮助到你
Laplie Anderson回答了一些小改进:
- 如果找不到资源,则抛出exception
- 忽略包含
[
和:
字符的路径
TypesafePropertySourceFactory.java
import java.io.IOException; import org.springframework.core.env.PropertySource; import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.PropertySourceFactory; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigParseOptions; import com.typesafe.config.ConfigResolveOptions; public class TypesafePropertySourceFactory implements PropertySourceFactory { @Override public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException { Config config = ConfigFactory .load(resource.getResource().getFilename(), ConfigParseOptions.defaults().setAllowMissing(false), ConfigResolveOptions.noSystem()).resolve(); String safeName = name == null ? "typeSafe" : name; return new TypesafeConfigPropertySource(safeName, config); } }
TypesafeConfigPropertySource .java
import org.springframework.core.env.PropertySource; import com.typesafe.config.Config; public class TypesafeConfigPropertySource extends PropertySource { public TypesafeConfigPropertySource(String name, Config source) { super(name, source); } @Override public Object getProperty(String path) { if (path.contains("[")) return null; if (path.contains(":")) return null; if (source.hasPath(path)) { return source.getAnyRef(path); } return null; } }