配置文件是用来解耦的吗_一次配置,随处运行:解耦配置和运行时
配置文件是用来解耦的吗
重要要点
|
自瑞士信贷(Credit Suisse)和Oracle(Oracle)为Java EE配置启动JSR的大胆尝试逐渐过去以来,已经过去了两年。 消亡的原因很多,我们在这里未详细说明细节。 可以说,即使正式的JSR从未得到JCP执行委员会的批准,Java标准化配置的倡议也从未停止过。 在本文中,我将重点关注该计划的后续工作和当前状态。
为什么配置标准很重要?
在所有应用程序中,配置都是一个共同的横切关注点。 属性通常指定为键=值对,并以可加载到Java属性对象中的文件形式提供。 不幸的是,以Java运行的OSGI,Spring,Java EE,SE和其他框架和解决方案都提供了自己的配置API和格式。 他们中的许多人使用专有的XML格式,另一些人使用更现代的格式,例如Yaml。 在大多数情况下,Java EE甚至不支持动态或远程配置。 由于不同的配置格式,位置和冗余,在应用程序中组合不同的框架总是很麻烦。 所有这些都增加了不必要的复杂性,并且容易出错。 它会影响为一个应用程序编写的代码,但也会影响与周围系统的集成。 在过去的二十年中,Java在许多领域都发挥了巨大作用,为开发任何类型的应用程序创建了无与伦比的生态系统。 感觉很奇怪,像配置这样的常见问题缺少标准化的API,这将消除应用程序构建自己的解决方案并简化由不同涉众提供的已配置模块的集成的需求。
动机和背景
关于应该做什么和应该做什么配置的意见分歧很大。 结果,配置标准不应集中于配置什么或何时配置。 以此为驱动力,我们将现有的知识体系和实验代码库移至了名为Apache Tamaya的新孵化器项目中。 我们将早期讨论的重点放在了现有的想法和需求上,但最终退后了一步,从头重新定义了用例,并制定了一个有光泽的新实现。 鉴于配置是使用最广泛的跨领域问题之一,我们希望并期望这项工作将以某种形式出现,成为使整个Java生态系统受益的标准。
Tamaya的一些功能包括:
- 定义一组配置注释(tamaya-inject-api),可以将其添加到客户端代码以注入配置的值。 无论您的代码是作为普通的旧Java SE应用程序运行,还是在CDI容器或Spring环境中运行,注释均以统一的方式工作。 甚至支持OSGi服务。
- Tamaya支持不仅限于
String
值,还可以是任何Java类型,只要注册了PropertyConverters
即可从原始配置值(String
类型)派生类型化的值,例如,作为Date或URL。 - 另外,Apache Tamaya提供了无数的扩展和集成,并提供了根据用户要求自定义配置运行时的功能。 (这通过允许用户为他们的系统选择最合适的功能来解决配置复杂性的挑战)。 一个不错的好处是,除了测试范围外,所有扩展都不依赖于核心模块,它提供了执行我们的测试用例的功能实现。
总而言之,在Apache Tamaya的最新版本0.2孵化中,我们提供了功能全面的配置解决方案,可提供稳定且经过验证的API / SPI。 众多扩展已成功证明,以可重用和可扩展的方式对配置进行建模是可行的。
另外,我们定义了一个完整的基于注释的注入API,该API还提供对Java EE / CDI(和其他一些运行时平台)的支持。因此,现在该是重新讨论是否将我们的想法植入JSR的讨论了。 为此,每个Java发烧友和专家(包括当前的读者)都应该对Tamaya有所了解,并提供反馈,或者在社交媒体上大声疾呼。 不用说,我们目前没有数百万美元的营销预算,因此,我们将不胜感激。
现在让我们更深入地研究一下,“配置一次,到处运行”对于您作为开发人员的日常工作意味着什么。
用例
Apache Tamaya涵盖了各种用例,并且由于我们的模块化结构,您可以轻松添加尚不存在的任何需求。 概览Tamaya最重要的功能是:
- 完整且统一的Java API,用于基于程序或基于注释的配置访问; 适用于Java SE和EE环境。
- 支持诸如Spring和OSGI之类的框架。
- 支持动态充实(允许您引入其他属性源)。
- 作为单个属性或完整配置访问的键/值的过滤。 这允许更改,省略或添加键和值(例如,密码被屏蔽)。 否则,它将允许基于访问控制列表来限制访问。
- 默认情况下,配置被组织为PropertySource的有序列表,每个都有一个序数值。 PropertySources可以提供任何类型的属性,例如系统属性,环境属性,基于文件的属性或任何类型的源和格式。 具有较高序数的PropertySource基本上会覆盖(默认情况下)具有较低序数的PropertySources提供的条目(一个PropertySource实现单个资源的映射。)
- 如上文所述,更高有效值(由PropertySource提供的具有较高序数值的值)将覆盖具有相同键重要性较低的值。 为了支持自定义行为更合适的用例,用户定义的组合策略支持更灵活的覆盖机制。 例如,当配置一个
List
值时,我们可以定义一个行为来组合两个值“a, b”
和“c, d, e”
以产生“a, b, c, d, e”
。 - 支持配置文件中的占位符,例如
${sys:a.sys.property}, ${url:config.server:8090/v1/abc}, ${conf:cross.ref}
。 - 支持多种配置格式,例如Yaml,Json,properties等。
- 与新的专用配置后端(例如e tcd和C onsul)集成 。
- 支持动态和灵活的资源位置,例如在数据库,Consul或etcd或文件中。
- 支持动态配置处理,事件和可变配置。
尚未发布的功能(计划进行0.3培养 )包括:
- 支持配置使用情况指标。
- 支持配置验证和文档,例如,为CLI -help命令选项生成输出。
- 易于使用的基于YAML的配置DSL。
- 用于可视化和管理配置的Web组件。
让我们看一下“一次配置,随处运行”的一些示例。 使用Tamaya实现可配置组件通常包括以下步骤:
- 实施组件。
- 确定可配置的方面。
- 定义键和内联合理的默认值,从而启用“按配置进行约定”。
- 添加提供与目标运行时集成的Tamaya库,也许是Java EE servlet容器或Spring Boot应用程序。
- 将组件与硬编码的默认值一起使用,然后继续进行常规的实现工作,而无需任何进一步的配置。 您可以使用Tamaya记录并观察您的配置,并在以后将有效文件格式或配置后端分配为简单的依赖项。
实施SupportContact类
让我们考虑一个简单的示例:假设我们正在构建一个组件,为应用程序提供支持联系信息。 SupportContact
组件的定义如下:
package com.mycompany;
public class SupportContact{
private String supportOrganization;
private String phoneNumber;
private String email;
private boolean supports24x7;
private Collection<Contact> supportContacts;
public String getSupportOrganization(){
return supportOrganization;
}
public String getPhoneNumber(){
return phoneNumber;
}
[...]
}
要配置此类,我们可以实现一个构造函数来执行配置逻辑:
public SupportContact(){
this.supportOrganization =
ConfigurationProvider.getConfiguration()
.getOrDefault(“support.organization”, “N/A”);
this.phoneNumer =
ConfigurationProvider.getConfiguration()
.getOrDefault(“support.phone”, “N/A”);
[...]
}
这种声明式访问实际上有效,但是大多数使用像Spring这样的依赖注入框架的开发人员都希望使用tamaya-injection模块来配置实例:
public SupportContact(){
ConfigurationInjection.getConfigurationInjector()
.configure(this);
}
配置代码也可以位于外部配置类中,而原始类保持不变。 默认情况下,所有内置Java类型(例如String, boolean,
和int
)以及java.math.BigDecimal
和BigInteger
类型均受支持。 通过添加tamaya-collections
扩展模块作为依赖项,也支持集合类型。 Tamaya的ConfigurationInjector
,用于将配置注入POJO的接口,如果不存在配置注释,则尝试配置使用最佳猜测方法找到的所有属性。 它将包,类和字段名称组合到候选关键字的有序列表中,并尝试查找相应的配置值。 遇到的第一个非空值被注入。 未定义的属性(其中没有任何候选键与值匹配)会记录警告,但不会引发异常。 这样就可以使用标准Java在代码中提供默认值,并根据需要使用属性覆盖默认值:
private String supportOrganization = “N/A”;
private String phoneNumber = “N/A”;
private String email = “N/A”;
private boolean supports24x7 = true;
private Collection<Contact> supportContacts = new ArrayList<>();
深入探讨,Tamaya的属性映射机制会将这些条目映射到以下候选键列表:
com.mycompany.SupportContact.supportOrganization
SupportContact.supportOrganization
supportOrganization
com.mycompany.SupportContact.phoneNumber
SupportContact.phoneNumber
phoneNumber
com.mycompany.SupportContact.email
SupportContact.email
email
com.mycompany.SupportContact.supports24x7
SupportContact.supports24x7
supports24x7
com.mycompany.SupportContact.supportContacts
SupportContact.supportContacts
supportContacts
通过使用tamaya-injection-api扩展模块定义的Tamaya注释,还可以使用更明确的方法来分配用于配置代码的配置键。 使用这种方法,您可以按如下方式注释类和属性:
@Config(“organization”, defaultValue=“N/A“)
private String supportOrganization;
@Config(value=“phone“, defaultValue=“N/A“)
private String phoneNumber;
@Config(defaultValue=“N/A“)
private String email;
@Config(defaultValue=“true“)
private boolean supports24x7;
@Config(“contacts”, defaultValue=“Admin:admin“)
private Collection<Contact> supportContacts;
}
这使您可以完全控制Tamaya的属性映射机制如何映射这些条目:
support.organization
support.phone
support.email
support.supports24x7
support.contact
因此,我们可以将这些属性放入一个简单的.properties
文件中:
support.organization=MyCompany
support.phone=+41(1)23 553 234
support.email=chief-admin@mycompany.com
support.supports24x7=true
support.contact=Chief Admin:Peter Cole;Advisory Admin:John Doe
...或Yaml文件:
---
support:
organization: MyCompany
phone: +41(1)23 553 234
email: chief-admin@mycompany.com
supports24x7: true
contacts:
- Chief Admin
Peter Cole
Advisory Admin
John Doe
Tamaya将为您处理详细信息,例如配置格式,位置和替代。 为了发现项目的配置挂钩的位置, tamaya-model扩展可以提供已定义配置属性的列表,还可以测量其使用情况。
塔马亚和足够灵活,你可以把它连接,与任何后端您(或您的客户)使用,因此开发人员可以专注于怎样进行配置。 如何成为可以独立处理的集成方面。
注意事项 :
实际上,Tamaya提供了几种与配置后端集成的选项:
- 将一些测试配置添加到
META-INF/javaconfiguration.
(测试)类路径中的属性。 这是默认位置,开箱即用(如果不需要,可以将其关闭)。 - 编写您自己的
PropertySource
并将其注册到JDKServiceLoader
以加载任何配置(包括动态值)。 - 向aTamaya配置
meta-model
添加依赖关系,该依赖关系提供并注册预先实现和配置的PropertySources和PropertySourceProvider
实例。 此元模型定义了配置的映射,位置和格式。 该文件可以由专门的平台工程团队创建和管理,并在全球范围内发布给组织中的所有开发人员,以确保以统一的方式配置应用程序或服务。 - 从下一个0.3-incubating版本开始,计划使用元模型DSL,这将使您可以像记录日志配置一样描述您的配置运行时系统。 通过这种方法,可以定义和配置一组概要文件和格式,并且为每个概要文件分配PropertySources列表和基本序数值。 始终考虑定义为“默认值”的配置文件。 当未设置任何配置文件时,“默认有效”定义活动配置文件(除任何默认配置文件外),而“评估”允许定义如何确定当前活动的配置文件(使用Tamaya的占位符机制)。 例如,以下Yaml文件定义了完整的配置系统:
TAMAYA:
PROFILES_DEF:
- profiles: DEFAULTS,DEV,TEST,PTA,PROD
- supports-multi: false
- defaults: DEFAULTS
- default-active: DEV
- evaluation: sys-property:ENV, env-property:ENV
FORMAT-DEF:
- formats: yaml, properties
- suffixes: yml,yaml,properties
PROFILES:
<ALL>:
- sources:
- named:env-properties # provider name, or class name
- named:main-args
- classpath:META-INF/defaults/**/*.SUFFIX
- file:${config.dir}/defaults**/*.SUFFIX ?optional=true
- classpath:META-INF/config/**/*.SUFFIX
- named:sys-properties
DEFAULTS:
- prio: 0 # optional
- filters:
- include:DEFAULTS\.*?ignoreCase=true
- exclude:_\.* # removes all meta-entries
DEV:
- prio: 100 # optional
- filters:
- include:DEV\.*?ignoreCase=true
[...]
PROD:
- prio: 1000 # optional
- filters:
- include:PROD\.*?ignoreCase=true
类型化配置模板
作为注释类的替代方法,您可以选择使用Tamaya的模板功能,该功能使用类型化的接口来定义配置。 例如,要配置一个简单的Web服务器,可以编写以下配置界面,并用Tamaya的注释丰富它:
@ConfigSection(“server”)
public interface ServerConfig{
@Config(defaultValue=”8080”);
int getPort();
@Config(defaultValue=”/”);
int getRootContext();
}
然后可以使用CDI直接注入配置:
@Inject
ServerConfig serverConfig;
Tamaya将基于注释和当前配置后端来实现Bean。
使用SupportContact组件
纯Java SE
如上文所述,您可以使用Tamaya的SE注入模块将属性注入Java SE应用程序:
SupportContact contact = new SupportContact();
ConfigurationInjection.getConfigurationInjector()
.configure(contact);
Java EE
在Java EE中,CDI是首选的生命周期管理器,因此我们告诉CDI“注入”我们的组件(CDI实际上将使用@Dependent伪作用域创建一个组件)。 为此,您必须添加tamaya-injection-cdi扩展模块,该模块利用CDI和Tamaya的配置注入机制,因此最终,您只需让CDI注入您的类即可:
@Inject
private SupportContact contact;
弹簧
尽管采用Spring方式,Spring也使用CDI方法。 只需添加tamaya-spring集成模块,您的所有Spring Bean都是可配置的。 因此,您可以将SupportContact bean添加到Spring上下文中,并在注入之前对其进行隐式配置:
@AutoWire
private SupportContact contact;
威特克斯
作为最后一个示例,我们想展示为您的项目添加Tamaya的配置灵活性有多么容易。 因此,我们来看vertx.io 。 在Vertx主要抽象是一个v erticle 。 为了使事情简单,我们将使顶点扩展可重用的基类,我们将调用ConfigurableVerticle
:
public abstract class ConfigurableVerticle extends AbstractVerticle{
public ConfigurableVerticle(){
ConfigurationInjection.getConfigurationInjector()
.configure(this);
}
}
现在,我们可以使用Tamaya的注释配置我们的顶点:
public class MyVerticle extends ConfigurableVerticle{
@Config(value=”monitoring.count-limit”, defaultValue=”100”)
private int countLimit;
[...]
}
当然,这是一个相当简单的例子。 但是它表明,可以配置与目标运行时分离的组件,而不会给开发人员的日常工作增加任何显着的复杂性。
连接配置后端
使用默认的javaconfiguration.properties
Tamaya默认情况下从类路径读取环境属性,系统属性和META-INF/javaconfiguration.properties
。 系统属性取代其他任何属性。 因此,我们可以配置组件:
- 通过设置相应的环境属性。 例如,在Docker中运行时,我们可以添加以下环境属性:
ENV support.supportOrganization foo
ENV support.phoneNumber bar
ENV support.email foo2
ENV support.supportContacts bar2
- 通过设置系统属性,例如
Dsupport.supportOrganization=Tamaya
- 或者通过将配置添加到
META-INF/javaconfiguration.properties
并确保资源在您的类路径上可见。
这一切仍然非常简单,正如我提到的,我们将添加具有0.3-incubating的元配置DSL,这将使其更加灵活。
添加测试配置
测试是问题的温床,尤其是当测试在并行线程中运行时,该配置将在全局范围内共享。 仅从本质上来说,这不是一个问题。 但是,在测试中,您通常希望测试各种配置以确保您的组件按预期运行,因此在这种情况下共享配置可能最终会出现在竞争条件下,从而使测试结果无效。 解决此问题的一种方法(可能在下一个版本中引入)是实现和注册具有很高序数的单个PropertySource
。 顺序值将覆盖现有属性源提供的任何现有属性。 因此,我们只需要确保仍在多个线程之间共享的PropertySource
在内部使用ThreadLocal
提供隔离即可。 连同一些静态访问器,我们的配置测试设置已可以使用:
public TestConfig extends BasePropertySource{
private static ThreadLocal<Map<String,String>> maps =
new ThreadLocal<>(){
[...]
};
public TestConfig(){
super(100000); // default ordinal
}
@Override
public Map<String,String> getProperties(){
return maps.get();
}
public static String put(String key, String value){
return TestConfig.maps.put(key, value);
}
public static String remove(String key){
return TestConfig.maps.remove(key);
}
}
然后,我们可以通过将以下行添加到META-INF/services/org.apache.tamaya.spi.PropertySource
,向ServiceLoader
注册PropertySource
:
com.mycompany.TestConfig
现在我们可以直接在我们的JUnit代码中使用它:
public class TestSupportContact{
@Before
public void setup(){
TestConfig.put(“support.email”, “test@127.0.0.1”);
}
@Test
public void test(){
[...]
}
@After
public void teardown(){
TestConfig.remove(“support.email”);
}
}
添加远程后端
我们的示例组件配置基于类路径资源或本地和测试文件。 对于大多数情况,这是一个合理的解决方案。 但是,让我们想象一下,在完成应用程序之后,我们的客户了解到etcd作为分布式键/值存储,并要求我们支持etcd作为后端。 使用Tamaya,您可以选择:
- 实施并注册自定义
- 使用Tamaya的etcd扩展模块。
第一种方法类似于我们之前看到的测试方案。
第二种方法并不困难。 我们只是将所需的条目添加到Tamaya的扩展模块中。 (如果有冲突或特殊的映射要求,可以设置一些系统属性来适应模块的行为,包括正在查找的etcd服务器)。 这里的重点是仍然不需要更改代码中的任何内容 。 您的Java代码与配置位置以及如何覆盖无关。 这意味着我们已经成功地将配置与其后端分离: “配置一次,到处运行。”
总结与展望
我们仅看到了标准化配置API为Java生态系统提供的一些好处。 在没有标准的情况下,每个人都按照自己的方式做。 本文的目标是引发公众讨论并收集您的意见:我们是否应该在9月的下一届JavaOne会议上将其作为新的JSR提出? 从范围的角度来看,它应该相对紧凑:
- 我们讨论的利用CDI的一组注释。
- 针对CDI不可用的用例的最小Java API。
- 提供定制扩展的扩展点的SPI。 Tamaya SPI在保持其简单性的同时必须非常灵活,因此这将是一个开始讨论的好地方。
基本上,它可以作为Java EE JSR运行,基于Apache所做的工作,结果类似于“重新加载Java EE配置JSR”。 由于它基本上与CDI 1.1兼容,并且对Java EE平台没有任何其他要求,因此我认为仍可以将其添加到当前的Java EE版本中。
不管JSR的决定如何,Tamaya都在寻找其他提交者。 因此,如果您对该主题感兴趣,请与我们联系!
翻译自: https://www.infoq.com/articles/Apache-Tamaya-Configure-Once-Run-Everywhere/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1
配置文件是用来解耦的吗
配置文件是用来解耦的吗_一次配置,随处运行:解耦配置和运行时相关推荐
- 解耦,未解耦的区别_受干净架构启发的解耦php架构
解耦,未解耦的区别 This article would not be possible without the help of Rodrigo Jardim da Fonseca, Edison J ...
- ssm 返回json配置_摆脱困境:将运行时配置作为JSON返回
ssm 返回json配置 如果需要确定部署到远程服务器的Spring Web应用程序的运行时配置,则需要读取从远程服务器找到的属性文件. 这很麻烦. 幸运的是,有更好的方法. 这篇博客文章描述了我们如 ...
- 【云原生】 初体验阿里云Serverless应用引擎SAE(三),挂载配置文件使应用的配置和运行的镜像解耦
目录 一.前言 二.SAE配置 1.创建配置项 2.配置SAE Nginx服务 效果 1.[云原生] 初体验阿里云Serverless应用引擎SAE(一),部署Nginx服务 2.[云原生] 初体验阿 ...
- 异常信息配置文件已被另一个程序更改_抢先目睹:SpringBoot2.4配置文件加载机制大变化
翻译: 冷冷.如梦技术 原文链接:spring.io/blog/2020/0- Spring Boot 2.4.0.M2 刚刚发布,它对 application.properties 和 applic ...
- Spring Boot概述与入门特点配置方式注入方式yim配置文件与多文件配置Spring Boot自动配置原理lombok应用
1. Spring Boot概述 Spring Boot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品: 首页Spring Boot简介可以 ...
- 【数据库Redis】Redis五种基本数据结构以及三种配置方式——默认配置、运行配置、配置文件启动
文章目录 一.初识Redis 1.1 了解Redis 1.2 Redis特性 1.3 Redis使用场景 Redis不适合场景 1.4 用好Redis的建议 1.5 正确安装并启动Redis 在Lin ...
- nacos 本地测试_微服务架构系列之Nacos 配置核心概念
上次讲了<微服务架构之Nacos配置中心之配置MySQL数据库>,本次讲述Nacos 配置核心概念.原作者:哈喽沃德先生,谢谢关注哈喽沃德先生. 1.配置 为什么需要配置?概念. 在系统开 ...
- 灰度值取值范围_灰度实战(二):Apollo配置中心(2)
CSDN博客地址(关注,点赞) 人工智能推荐 GitHub(Star,Fork,Watch) [前言] 在上一篇博文<灰度实战(一):Apollo配置中心(1)>中讲解了如何搭建Apoll ...
- ftp可以传输什么类型文件_使用FTP文件传输典型案例配置
亲爱的小伙伴们 咱们8月整月开课计划已出 座位有限 感兴趣的小伙伴赶紧预约啦 建策科技8月开班计划 如下图所示:两台路由器连接,我们将FTP服务器和FTP客户端中的文件(例如:配置文件.系统升级文件等 ...
最新文章
- 声音匹配_如何调节人声音色方法如下
- python知识点总结(有空就往里面添加)
- Python内置函数(62)——exec
- C++小白课本练习3
- Oracle云安全服务半年收获100万用户
- ubuntu中mysql安装失败
- python正则表达式练习题
- 【人脸表情识别】基于matlab GUI CNN人脸表情识别【含Matlab源码 787期】
- 勤哲excel服务器2017应用及无限用户
- linux脚本 exe,Powershell下载并运行exe文件
- 计算机电路电子技术试题答案,数字电子技术试题库及答案解析知识分享
- python爬取网易云音乐数据
- python怎么计算复利_用python计算复利和年化收益率
- 学习关于 2D 和 3D 姿势估计的知识
- linux如何安装qq输入法
- OSS回源的几种方式和应用场景
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
- python快速接手别人的代码_Python 爬虫代码,网上找的别人的,但是报错,求高手指点...
- 2013年计算机试题(三),2013年计算机等级考试(一级Ms Office)经典试题(三)及答案...
- Androidq下编译efr32mg21
热门文章
- 河北省计算机专业本科院校排名,河北本科院校排名:河北大学仅排第二,第一是一所双非院校...
- zoom手机设置分组讨论,zoom分组讨论功能在哪里
- 网赚APP的“俄罗斯套娃”游戏
- 基础篇章:React Native之 ScrollView 的讲解
- 全球疫情可视化实时更新
- 设备树下的字符设备驱动框架
- WindowManager
- 超哥笔记--shell 基本命令(4)
- 百度之星2017资格赛 1003 度度熊与邪恶大魔王 完全背包
- unable to negotiate with xxxxx port xxx: no matching host key type found. Their offer: ssh-rsa