当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Boot自定义配置属性源(PropertySource)

Spring Boot自定义配置属性源(PropertySource)

2019年07月19日  | 移动技术网IT编程  | 我要评论

贾超风,什么是可燃冰,邯郸汽车站

配置覆盖优于profile

在生产实践中,配置覆盖是解决不同环境不同配置的常用方法。比如用生产服务器上的配置文件覆盖包内的文件,或者使用中心化的配置服务来覆盖默认的业务配置。

相比于profile机制(比如maven的profile、spring boot的profile-specific properties),即不同环境使用不同的配置文件,覆盖的方式更有优势。程序员在开发时不需要关心生产环境数据库的地址、账号等信息,一次构建即可在不同环境中运行,而profile机制需要将生产环境的配置写到项目资源文件中,而且要为不同环境使用不同的构建参数或者运行参数。

spring提供了灵活的配置扩展能力,有多种方式将自定义的属性源,将集成进来,可以轻松地实现配置覆盖。

本文基于spring boot 1.4.8/spring 4.3.12编写

使用@propertysource注解实现自定义配置文件和配置覆盖

@configurationproperties
@configuration
public class demoproperties {
  // properties with getter/setters
}
@propertysource(value = {
    "test.properties",
    "file:/etc/test.properties",
},
    ignoreresourcenotfound = true)
@configuration
public class demoautoconfiguration {

  @autowired
  private demoproperties demoproperties;

  @postconstruct
  public void init() {
    system.out.println(demoproperties);
  }
}

spring支持使用propertysource注解引入自定义配置文件,其中"test.properties"将使spring从classpath下加载该文件,"file:/etc/test.properties"将使spring从文件系统加载/etc/test.properties文件,ignoreresourcenotfound = true使spring忽略文件加载失败的异常,即配置文件是可选的。

同时,由于"file:/etc/test.properties"位于"test.properties"之后,这使得文件系统的配置文件可以覆盖classpath下的配置。

自定义属性源工厂

如果想要更加灵活的自定义属性源,比如实现从中心化的配置服务加载配置,可以通过实现propertysourcefactory接口,并通过配置propertysource注解的factory参数来实现。

@configuration
@propertysource(value = ""/*placeholder*/,
    factory = compositepropertysourcefactory.class)
public class compositeconfigautoconfiguration {
}

value字段用于指定配置源对应的资源文件,如果不需要使用资源文件,可以配置为任意值,参数值将会被传递到factory参数的createpropertysource方法。

如果ignoreresourcenotfound字段指定为true,那么factory抛出的异常将被忽略,否则将导致启动失败。有的时候,直接把启动失败暴露出来不失为一种好的做法。

propertysourcefactory接口的定义如下:

/**
 * strategy interface for creating resource-based {@link propertysource} wrappers.
 *
 * @author juergen hoeller
 * @since 4.3
 * @see defaultpropertysourcefactory
 */
public interface propertysourcefactory {

 /**
 * create a {@link propertysource} that wraps the given resource.
 * @param name the name of the property source
 * @param resource the resource (potentially encoded) to wrap
 * @return the new {@link propertysource} (never {@code null})
 * @throws ioexception if resource resolution failed
 */
 propertysource<?> createpropertysource(string name, encodedresource resource) throws ioexception;

}

需要注意的是propertysourcefactory的加载时机早于spring beans容器,因此实现上不能依赖于spring的ioc。

propertysourcefactory要求实现类返回propertysource。propertysource是spring属性(或者说配置)功能的核心接口,有很多实现,比如:

  1. resourcepropertysource 从resource加载propertysource
  2. propertiespropertysource 从properties文件加载propertysource
  3. systemenvironmentpropertysource 从系统环境变量加载propertysource
  4. mappropertysource 包装一个map为propertysource(adapter模块)
  5. compositepropertysource 支持将若干propertysource进行组合(composite模式)

实际实现类远不如这些,具体的可以阅读spring文档或源码。

在自定义属性源时比较常用的是mappropertysource和compositepropertysource。

mappropertysource可以用于将自己加载的属性数据包装,参考其构造方法。

public mappropertysource(string name, map<string, object> source) {
 super(name, source);
}

后者可以通过组合装载多个属性源并自定义覆盖顺序。例如:

propertysource<?> packageinsidepropertysource = packageinsidepropertysourceiterateloader.loadpropertysource(compositepropertysource);
compositepropertysource.addpropertysource(packageinsidepropertysource);

propertysource<?> outerfilepropertysource = outerfilepropertysourceiterateloader.loadpropertysource(compositepropertysource);
// 优先级高于前者
compositepropertysource.addfirstpropertysource(outerfilepropertysource);

addfirstpropertysource方法可以设置传入的propertysource为最高优先级(在此compositepropertysource内部),addpropertysource方法则相反,放在后面的优先级更低。

加载依赖jar包中所有同名配置文件

直接从classpath加载配置文件,要求文件必须存在于classpath中。考虑在web项目中,如果文件存在于某个依赖的jar包中,即位于web-inf/lib/xxx.jar中,此时基于classpath无法直接加载。此时可以使用spring提供的pathmatchingresourcepatternresolver,按资源名称扫描所有jar包来实现目的。

private list<resource> getpackageinsideresourcesbypattern(string resourcename) throws ioexception {
 string resourcepathpattern = resourcepatternresolver.classpath_all_url_prefix + hbootconfigconstants.configs + resourcename;
 resourcepatternresolver resourcepatternresolver = new pathmatchingresourcepatternresolver();
 return arrays.aslist(resourcepatternresolver.getresources(resourcepathpattern));
}

然后就可以使用resourcepropertysource从resource构建propertysource传给spring。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网