加入 Capa,共建社区:https://github.com/capa-cloud/capa-java/issues
欢迎来到 Capa 文档库!
加入 Capa,共建社区:https://github.com/capa-cloud/capa-java/issues
欢迎来到 Capa 文档库!
Capa 为 Java 应用提供统一的云运行时 API,并通过可替换的 SDK 组件适配不同基础设施。
让代码实现"一次编写,随处运行"。
借助Capa体系,使你的Java应用在改动量较小的情况下,拥有跨云、混合云运行的能力。
Capa项目基于Mecha架构的设计理念,使用 富SDK模式 提供Multi-Runtime的标准API。
您可以简单的将Capa项目理解为 Dapr / Layotto 等Sidecar模式项目的SDK实现版本。
欲要理解Mecha架构的设计思路,请阅读以下文章:
MOSN子项目Layotto:开启服务网格+应用运行时新篇章
基于Mecha架构理念的Multi-Runtime,以Sidecar的方式提供标准API的功能,看起来似乎是最合理的选择。
那为什么不直接使用Dapr/Layotto等项目,而是选择开发 富SDK模式 的Capa项目呢。
概括:以Dapr为代表的Sidecar架构是未来,但现有的很多企业和系统很难一步到位的升级到Sidecar架构,富SDK架构将会长期的存在下去。
引申:面对庞大的Java系统体系,Capa项目将使用富SDK模型支持Java系统向Mecha架构过渡。在Dapr等项目成熟后,也可以无缝衔接到Sidecar架构。
关于此问题的具体讨论请参考:
Capa API设计follow社区标准,请参考 Dapr / Layotto 等开源项目的API定义。
API定义放置于以下独立仓库中,与Capa项目解绑,希望发展成为社区的API标准定义:
由于目前Dapr API和Dapr项目强绑定,但我们希望这套API能够成为整个社区的标准,所以Capa将API定义放在独立仓库中,并时刻和上游社区标准保持同步。
我们希望后续Dapr能够将其API独立部署出来,与Dapr项目相解耦,成为整个社区的标准。
关于此项的讨论,请查看:
Capa(Java SDK)是面向Java应用实现Mecha架构的SDK解决方案,它目前支持以下领域的特性:
设计思路:标准API + 可拔插可替换的SDK组件 模式
在不同的分布式中间件领域,Capa提供与具体中间件API无关的统一的标准编程API。 所以应用程序在使用Capa编程时不需要依赖任何具体的中间件API,只需要依赖Capa的标准编程API即可。
在部署到不同的目标环境时,Capa将会装载标准API的不同实现类到应用程序中。当调用统一的编程API时,底层运行时会适配到不同的具体中间件SDK实现。
中间件团队需要针对不同目标环境,开发标准API在目标环境下的实现类即可;而应用代码可以拥有"一次编写,随处运行"的开发体验。
Capa module划分主要为以下几个部分:
应用程序编程时只需要依赖sdk即可,并使用SDK模块中定义的统一编程API。
在运行前,会将具体的SPI实现包引入进去,作为统一编程API的具体实现。
For a Maven project, add the following to your pom.xml file:
<project>
...
<dependencies>
...
<!-- Capa's core SDK with all features. -->
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-sdk</artifactId>
<version>1.11.13.2.RELEASE</version>
</dependency>
...
</dependencies>
...
</project>
Sample implementation library:
<project>
...
<dependencies>
...
<!-- Capa's core SDK with all features. -->
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-sdk-spi-demo</artifactId>
<version>1.11.13.2.RELEASE</version>
</dependency>
...
</dependencies>
...
</project>
Try the following examples to learn more about Capa’s Java SDK:
如果要使用原生的Capa API,您的遗留系统需要面对较大的重构工作量。
为了使迁移做到低成本,我们可以复用目前使用到的中间件API。
通过开发一个适配层项目(提供相同的注解/接口调用方式),将原中间件API的实现更改为Capa API。
如此一来,应用程序只需要更改很少的代码(例如更换注解/接口的路径名)即可迁移到Capa架构。
关于该问题的讨论,请查看:
Java sdk design 调研:能否复用业界已有的事实标准
考虑到异步调用模式,以及非阻塞IO的使用,我们原生提供Reactor的编程模型,您也可以通过其block()方法使用同步调用的功能。
The Java SDK for Capa is built using Project Reactor. It provides an asynchronous API for
Java. When consuming a result is consumed synchronously, as in the examples referenced above, the block() method is
used.
The code below does not make any API call, it simply returns the Mono publisher object. Nothing happens until the application subscribes or blocks on the result:
Mono<String> result=capaRpcClient.invokeMethod(SERVICE_APP_ID,"say","hello",HttpExtension.POST,null,TypeRef.STRING);
To start execution and receive the result object synchronously, use block(). The code below shows how to execute the
call and consume an empty response:
Mono<String> result=capaRpcClient.invokeMethod(SERVICE_APP_ID,"say","hello",HttpExtension.POST,null,TypeRef.STRING);
String response=result.block();
Most exceptions thrown from the SDK are instances of CapaException. CapaException extends from RuntimeException,
making it compatible with Project Reactor.
感谢您对Capa的支持!
CapaConfigurationClient提供的配置能力,需要实现具体的实现类来适配不同的平台(通过继承CapaConfigStoreSpi抽象类),如示例DemoCapaConfigStore
通过spi机制实现对具体实现类的加载。具体配置过程为:在项目resources路径下,新增capa-component-configuration.properties文件。
在文件中新增属性key:“group.rxcloud.capa.component.configstore.CapaConfigStore”,value:“实现类的全路径”;新增属性key:“CONFIGURATION_COMPONENT_STORE_NAME”,value:“config store name"示例如下:
//capa-component-configuration.properties文件
group.rxcloud.capa.component.configstore.CapaConfigStore=group.rxcloud.capa.spi.demo.configstore.DemoCapaConfigStore
CONFIGURATION_COMPONENT_STORE_NAME=DEMO CONFIG
调用相应Configuration API进行应用级配置管理
public final class CapaConfigStoreClientProvider {
private static volatile CapaConfigurationClient client;
public static CapaConfigurationClient getClient() {
if (client == null) {
synchronized (CapaConfigStoreClientProvider.class) {
if (client == null) {
StoreConfig storeConfig = new StoreConfig();
storeConfig.setStoreName(Optional.ofNullable(CapaProperties.COMPONENT_PROPERTIES_SUPPLIER.apply("configuration").getProperty("CONFIGURATION_COMPONENT_STORE_NAME")).orElse("UN_CONFIGURED_STORE_CONFIG_NAME"));
client = new CapaConfigurationClientBuilder(storeConfig).build();
}
}
}
return client;
}
private CapaConfigStoreClientProvider() {
}
}
//拿到单例client
private static final CapaConfigurationClient client = CapaConfigurationClientSingleton.getClient();
//getConfiguration()其中一个重载方法
Mono<List<ConfigurationItem<User>>> configMono = client.getConfiguration(new ConfigurationRequestItem(),TypeRef.get(User.class));
//getConfiguration()另一个重载方法
Mono<List<ConfigurationItem<User>>> configMono = client.getConfiguration("config",
SERVICE_APP_ID,
Lists.newArrayList("test.json"),
metaDataMap,
"group",
"label"
TypeRef.get(User.class));
//阻塞获取配置结果
List<ConfigurationItem<User>> config = configMono.block();
//本地存配置的变量
private SubConfigurationResp<String> cur;
//subscribeConfiguration()其中一个重载方法
Flux<SubConfigurationResp<User>> configFlux = client.subscribeConfiguration(new ConfigurationRequestItem(),TypeRef.get(User.class))
//subscribeConfiguration()另一个重载方法
Flux<SubConfigurationResp<User>> configFlux = client.subscribeConfiguration("config",
SERVICE_APP_ID,
Lists.newArrayList("test.json"),
metaDataMap,
"group",
"label"
TypeRef.get(User.class));
//订阅后续的变更并更新原数据
configFlux.subscribe(resp -> cur.setItems(resp.getItems()));
Mono<Void> configFlux = client.saveConfiguration(new SaveConfigurationRequest());
Mono<Void> configFlux = client.deleteConfiguration(new ConfigurationRequestItem());
ps:以上api存在重载方法,点击此处查询全部api列表
CapaRpcClient capaRpcClient = new CapaRpcClientBuilder().build();
Mono<byte[]> responseMono = capaRpcClient.invokeMethod(SERVICE_APP_ID,
"hello",
"hello",
HttpExtension.POST,
null,
TypeRef.BYTE_ARRAY);
byte[] response = responseMono.block();
感谢您对Capa的支持!
Configuration API的实现类Demo示例
ps:其中配置文件Demo中仅“group.rxcloud.capa.component.configstore.CapaConfigStore”和Configuration相关,其他property可以忽略
由于当前处于高速迭代中,代码和版本都很不稳定,文档可能不是最新版本,接入jar包版本和流程都可能会有较大改动,请查看最后更新时间,若和当前时间超过一周请咨询相关开发询问是否有较大改动!!!
**last updated on 2021/12/06
21/12/06/18:32 updated maven dependency
step1.引入maven依赖
<dependencyManagement>
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-framework-dependencies</artifactId>
<version>1.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-spi-aws-config</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
携程用户需要额外引入(目前jar包在携程私服上,仅限携程开发使用)
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-adaptor-group.rxcloud-qconfig</artifactId>
</dependency>
此外还提供foundation方法包,供使用方获取appId,provider,env,namespace,region使用(该foundation中的其他方法并未测试,请不要使用)
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-foundation</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>
ps:后续会统一放入capa-framework-dependencies bom中进行管理
step2.代码改动
public final class CapaConfigStoreClientProvider {
private static volatile CapaConfigurationClient client;
public static CapaConfigurationClient getClient() {
if (client == null) {
synchronized (CapaConfigStoreClientProvider.class) {
if (client == null) {
StoreConfig storeConfig = new StoreConfig();
//对应实现的storeName
storeConfig.setStoreName(storeName);
client = new CapaConfigurationClientBuilder(storeConfig).build();
}
}
}
return client;
}
private CapaConfigStoreClientProvider() {
}
}
private static final CapaConfigurationClient client = CapaConfigStoreClientProvider.getClient();
//根据自身填入storeName,appId
Mono<List<ConfigurationItem<User>>> configMono = client.getConfiguration(
storeName,
appId,
Lists.newArrayList("test.json"),
null,
"",
"",
TypeRef.get(User.class));
//阻塞获取配置结果
List<ConfigurationItem<User>> config = configMono.block();
//带超时时间的阻塞,自定义超时时间
List<ConfigurationItem<User>> config = configMono.block(Duration.ofSeconds(30));
subscribe
//本地存配置的变量
private static SubConfigurationResp<User> cur;
static {
//根据自身填入storeName,appId
Flux<SubConfigurationResp<User>> configFlux = client.subscribeConfiguration(
storeName,
appId,
Lists.newArrayList("test.json"),
null,
"",
"",
TypeRef.get(User.class));
//阻塞初始化配置
cur = configFlux.blockFirst();
//或使用带超时时间的阻塞初始化配置,自定义超时时间
cur = configFlux.blockFirst(Duration.ofSeconds(30));
//订阅变更并更新原数据
configFlux.subscribe(resp -> cur.setItems(resp.getItems()));
}
public String getConfig() {
User user = cur.getItems().get(0).getContent();
System.out.println("-----------------------------------age:" + user.getName());
}
使用adaptor包中的@QConfig注解替换QConfig中原来的@QConfig注解:将import qunar.tc.qconfig.client.spring.QConfig;修改为import group.rxcloud.capa.adaptor.group.rxcloud.qconfig.annotation.QConfig;
代码写法
@Service
public class JsonConfigService {
@QConfig("testjson.json")
private Person person;//非监听模式,支持热更新
@QConfig("testjson.json")
private void onChange(Person person) {//监听模式
System.out.println(person);
}
public String getPerson() {
return JSON.toJSONString(person);
}
}
private static final CapaConfigurationClient client = CapaConfigurationClientProvider.getClient();
//从adaptor中CapaConfigStoreClientProvider静态方法中获取storeName(必须)和appid(可选,可以自己从app.properties中读,也可以使用Foundation.app().getAppId() ps:此包为capa-foundation包提供的方法,仅在aws实现下使用)
Mono<List<ConfigurationItem<User>>> configMono = client.getConfiguration(
CapaConfigurationClientProvider.provideStoreName(),
Foundation.app().getAppId(),
Lists.newArrayList("test.json"),
null,
TypeRef.get(User.class));
//阻塞获取配置结果
List<ConfigurationItem<User>> config = configMono.block();
//或带超时时间的阻塞,自定义超时时间
List<ConfigurationItem<User>> config = configMono.block(Duration.ofSeconds(30));
subscribe
//本地存配置的变量
private static SubConfigurationResp<User> cur;
static {
//从adaptor中CapaConfigStoreClientProvider静态方法中获取storeName(必须)和appid(可选,可以自己从app.properties中读,也可以使用Foundation.app().getAppId() ps:此包为capa-foundation包提供的方法,仅在aws实现下使用)
Flux<SubConfigurationResp<User>> configFlux = client.subscribeConfiguration(
CapaConfigurationClientProvider.provideStoreName(),
Foundation.app().getAppId(),
Lists.newArrayList("test.json"),
null,
TypeRef.get(User.class));
//阻塞初始化配置
cur = configFlux.blockFirst();
//或使用带超时时间的阻塞初始化配置,自定义超时时间
cur = configFlux.blockFirst(Duration.ofSeconds(30));
//订阅变更并更新原数据
configFlux.subscribe(resp -> cur.setItems(resp.getItems()));
}
public String getConfig() {
User user = cur.getItems().get(0).getContent();
System.out.println("-----------------------------------age:" + user.getName());
}
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, String label, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, String label, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef<T> type);
@Override
Mono<Void> saveConfiguration(SaveConfigurationRequest saveConfigurationRequest);
@Override
Mono<Void> deleteConfiguration(ConfigurationRequestItem configurationRequestItem);
针对AWS云的设施基础现状下,选型AWS AppConfig为应用级别配置管理组件
继承CapaConfigStoreSpi抽象类,底层通过对appconfig的封装,实现相应的Configuration API
通过SPI机制引入相关实现类。具体流程为:
#capa-component-configuration.properties文件
group.rxcloud.capa.component.configstore.CapaConfigStore=group.rxcloud.capa.spi.aws.config.AwsCapaConfigStore
# configuration component store names
CONFIGURATION_COMPONENT_STORE_NAMES=aws.appconfig
# configstore aws app config env
CONFIG_AWS_APP_CONFIG_ENV=ENV
调用方通过使用Capa统一规范的Configuration API即可完成对应用级别配置的管理需求。
由于当前处于高速迭代中,代码和版本都很不稳定,文档可能不是最新版本,接入jar包版本和流程都可能会有较大改动,请查看最后更新时间,若和当前时间超过一周请咨询相关开发询问是否有较大改动!!!
last updated on 2021/12/06
step1.引入maven依赖
21/12/06/18:32 updated maven dependency
<dependencyManagement>
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-framework-dependencies</artifactId>
<version>1.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-spi-group.rxcloud-qconfig</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>group.rxcloud</groupId>
<artifactId>capa-adaptor-group.rxcloud-qconfig</artifactId>
</dependency>
step2.相关代码修改
@Service
public class JsonConfigService {
@QConfig("testjson.json")
private Person person;//非监听模式,支持热更新
@QConfig("testjson.json")
private void onChange(Person person) {//监听模式
System.out.println(person);
}
public String getPerson() {
return JSON.toJSONString(person);
}
}
private static final CapaConfigurationClient client = CapaConfigurationClientProvider.getClient();
//从adaptor中CapaConfigStoreClientProvider静态方法中获取storeName(必须)
Mono<List<ConfigurationItem<User>>> configMono = client.getConfiguration(
CapaConfigurationClientProvider.provideStoreName(),
appid,
Lists.newArrayList("test.json"),
null,
TypeRef.get(User.class));
//阻塞获取配置结果
List<ConfigurationItem<User>> config = configMono.block();
//带超时时间的阻塞,自定义超时时间
List<ConfigurationItem<User>> config = configMono.block(Duration.ofSeconds(30));
//本地存配置的变量
private static SubConfigurationResp<User> cur;
static {
//从adaptor中CapaConfigStoreClientProvider静态方法中获取storeName(必须)
Flux<SubConfigurationResp<User>> configFlux = client.subscribeConfiguration(
CapaConfigurationClientProvider.provideStoreName(),
appid,
Lists.newArrayList("test.json"),
null,
TypeRef.get(User.class));
//阻塞初始化配置
cur = configFlux.blockFirst();
//或使用带超时时间的阻塞初始化配置,自定义超时时间
cur = configFlux.blockFirst(Duration.ofSeconds(30));
//订阅变更并更新原数据
configFlux.subscribe(resp -> cur.setItems(resp.getItems()));
}
public String getConfig() {
User user = cur.getItems().get(0).getContent();
System.out.println("-----------------------------------age:" + user.getName());
}
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, String label, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(String storeName, String appId, List<String> keys, Map<String, String> metadata, String group, String label, TypeRef<T> type);
@Override
<T> Mono<List<ConfigurationItem<T>>> getConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef<T> type);
@Override
<T> Flux<SubConfigurationResp<T>> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef<T> type);
@Override
Mono<Void> saveConfiguration(SaveConfigurationRequest saveConfigurationRequest);
@Override
Mono<Void> deleteConfiguration(ConfigurationRequestItem configurationRequestItem);

ps:Service(appid:123)为举例,表示一个应用id为123的服务,下面直接缩写成ServiceA
针对携程全家桶的设施基础现状下,选型Qconfig为应用级别配置管理组件
继承CapaConfigStoreSpi抽象类,底层通过对Qconfig的封装,实现相应的Configuration API
通过SPI机制引入相关实现类。具体流程为:
#capa-component-configuration.properties文件
group.rxcloud.capa.component.configstore.CapaConfigStore=group.rxcloud.capa.spi.group.rxcloud.configstore.CtripCapaConfigStore
CONFIGURATION_COMPONENT_STORE_NAME=group.rxcloud.qconfig
#暂无配置
调用方通过使用Capa统一规范的Configuration API即可完成对应用级别配置的管理需求。
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object data, HttpExtension httpExtension, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Map<String, String> metadata, Class<T> clazz);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Class<T> clazz);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata, Class<T> clazz);
@Override
Mono<Void> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Map<String, String> metadata);
@Override
Mono<Void> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension);
@Override
Mono<Void> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata);
@Override
Mono<byte[]> invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, Map<String, String> metadata);
@Override
<T> Mono<T> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef<T> type);
下图为 Capa 的 RPC 在携程的 App Mesh 服务调用逻辑

实现 RpcServiceOptions(实际 RPC 调用需要的参数)和 CapaSpiOptionsLoader(加载 RpcServiceOptions 的接口)。
例如 AwsRpcServiceOptions 和 AwsSpiOptionsLoader
继承 CapaSerializeHttpSpi , 实现在携程 Service Mesh 的 RPC 调用。
例如 AwsCapaHttp
构建 capa-component-rpc.properties 文件,添加 group.rxcloud.capa.component.http.CapaHttp 和 group.rxcloud.capa.spi.config.CapaSpiOptionsLoader 对应的类的路径,以支持 SPI 方式加载对应的类。
例如:
group.rxcloud.capa.component.http.CapaHttp=group.rxcloud.capa.spi.group.rxcloud.http.AwsCapaHttp
group.rxcloud.capa.spi.config.CapaSpiOptionsLoader=group.rxcloud.capa.spi.group.rxcloud.config.AwsSpiOptionsLoader
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object data, HttpExtension httpExtension, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Map<String, String> metadata, Class<T> clazz);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Class<T> clazz);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata, TypeRef<T> type);
@Override
<T> Mono<T> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata, Class<T> clazz);
@Override
Mono<Void> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Map<String, String> metadata);
@Override
Mono<Void> invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension);
@Override
Mono<Void> invokeMethod(String appId, String methodName, HttpExtension httpExtension, Map<String, String> metadata);
@Override
Mono<byte[]> invokeMethod(String appId, String methodName, byte[] request, HttpExtension httpExtension, Map<String, String> metadata);
@Override
<T> Mono<T> invokeMethod(InvokeMethodRequest invokeMethodRequest, TypeRef<T> type);
下图为 Capa 的 RPC 在携程的 Service Mesh 服务调用逻辑

实现 RpcServiceOptions(实际 RPC 调用需要的参数)和 CapaSpiOptionsLoader(加载 RpcServiceOptions 的接口)。
例如 CtripRpcServiceOptions 和 CtripSpiOptionsLoader
继承 CapaSerializeHttpSpi , 实现在携程 Service Mesh 的 RPC 调用。
例如 CtripCapaHttp
构建 capa-component-rpc.properties 文件,添加 group.rxcloud.capa.component.http.CapaHttp 和 group.rxcloud.capa.spi.config.CapaSpiOptionsLoader 对应的类的路径,以支持 SPI 方式加载对应的类。
例如:
group.rxcloud.capa.component.http.CapaHttp=group.rxcloud.capa.spi.group.rxcloud.http.CtripCapaHttp
group.rxcloud.capa.spi.config.CapaSpiOptionsLoader=group.rxcloud.capa.spi.group.rxcloud.config.CtripSpiOptionsLoader
在跨云、混合云的场景下,我们希望应用程序可以使用一套代码,部署到不同的云环境上。在运行时,采用对应云环境提供的云原生实现方案。

定义与具体中间件无关的API层(无强绑定),使应用程序在编程时仅依赖该API层。 如此一来,应用本身便与具体中间件解耦;然后在部署到不同云环境时,将API的不同云的实现层加载到应用进程中。
全面的可观测指标度量规范定义

参考资料:https://segmentfault.com/a/1190000040061004
参考资料:https://www.51cto.com/article/691184.html

参考资料:https://segmentfault.com/a/1190000040061004
命名空间采用分级域名命名方式:
(顶级域名).一级域名.二级域名.三级域名.x.y.z
顶级域名应标识所属云(私有云、公有云)等基础设施。
但目前各云监控指标命名空间本身隔离,故不考虑加入顶级域名。
将云原生技术栈划分为4个领域,一级域名标识了所属的层级。
对应一级域命名空间为:
参考云原生技术栈图示给出的四个层次,使一级域名能够显示出Actuator所属的层级。

携程监控指标的一级域名主要有System、FrameworkName、App等等。
不过其技术栈领域的监控划分主要依赖于:使用不同看板进行呈现,相当于不同的监控平台本身对应于不同的技术栈领域。
应用层的监控主要还是以FrameworkName为主,反映出了携程是以框架为主体,框架就强绑定了该领域的概念(看到Dal就意味着关系型数据库、看到SOA就意味着RPC领域)。
Ops运维和管理领域:
应用层,应在二级域名进行应用类型的划分。
在这里,我们参考携程的应用类型设计,取运行时语言作为划分:
主要基于中间件维度进行定义:
以基础设施作为划分:
基于以上 一级域名(技术栈领域).二级域名(组件领域划分) 的命名空间,我们已经能够体现具体领域。
但每个领域,都可能有多种实现。
例如在中间件领域,携程命名空间做了 中间件-领域 的强绑定。
所以在三级域名的设计上,我们希望体现一些更细节的信息。
但没有必要像一二级域名一样,保持独立的语义。
故使用 小写+下划线 作为三级域名的格式标准。
包含更丰富的语义,但视觉上不像一二级域名一样强烈。
三级域名如果有更多细节需要体现,通过追加的方式进行拓展。
从实用性上来看,可以不使用三级域名,直接基于appId等。
如果要使用,参考携程应用类型定义。
组件领域,可能有多种 中间件实现 / 工具。
所以在三级域名上,我们希望体现 中间件/工具 的概念。
组件领域,中间件领域,都可能有多种编程语言的实现,其SDK内部逻辑不可能完全一致。
所以在三级域名上,我们希望体现 编程语言 的概念。
对于Fxc而言,目前已有(中间件名称_编程语言):
对于Inf而言,目前已有(工具/产品名称):
携程在监控命名上,强体现 框架名称。
中间件领域命名空间
使用 小写+下划线 作为 监控指标 名称的格式标准。
监控指标设计分为:Level0、Level1、Level2层次。
必需监控指标:
拓展监控指标
xx定义为 操作/业务 名称
请求量:
耗时:
成功率:
使用 小写+下划线 作为attributes的格式标准。
通过调用Capa SDK API的方式,管理应用级配置。底层通过SPI的方式注册适配各平台的实现类。
下图为Capa的Configuration服务调用逻辑

Capa Configuration API的设计参考了社区的规范
具体参数含义如下:
| 参数 | 含义 |
|---|---|
| storeName | 存储名称 |
| appId | 同一命名空间内的服务唯一ID |
| keys | 配置key列表 |
| metadata | 发送配置请求的元信息 |
| group | 配置组(Optional) |
| label | 配置标签(Optional) |
| type | 请求响应对象中的泛型对应的具体类型 |
| ConfigurationRequestItem | 请求对象 |
| ConfigurationItem | 获取配置的响应对象 |
| SubConfigurationResp | 订阅配置的响应对象 |
下图为 Capa 的 RPC 服务调用逻辑

Capa的 api 设计参照了社区的规范
具体参数含义如下:
| 参数 | 含义 |
|---|---|
| appId | 同一命名空间内的服务唯一ID |
| methodName | 被调用服务的方法名 |
| request | 要发送调用的服务请求 |
| httpExtension | HTTP请求方式 |
| metadata | 发送请求的元数据(GRPC)或者请求头(HTTP) |
| clazz | 请求响应的类型 |
| type | 请求响应的类型 |
| invokeMethodRequest | 请求对象 |
经过调研,发现AWS在RPC上
通过服务调用,应用程序可以使用 HTTP 这样的标准协议来发现并可靠地与其他应用程序通信。
下图为 Capa 的 RPC 服务调用逻辑

Capa的 api 设计参照了社区的规范
具体参数含义如下:
| 参数 | 含义 |
|---|---|
| appId | 同一命名空间内的服务唯一ID |
| methodName | 被调用服务的方法名 |
| request | 要发送调用的服务请求 |
| httpExtension | HTTP请求方式 |
| metadata | 发送请求的元数据(GRPC)或者请求头(HTTP) |
| clazz | 请求响应的类型 |
| type | 请求响应的类型 |
| invokeMethodRequest | 请求对象 |
本节包含 Capa SDK 组件的 API 参考文档。
Capa 为云应用开发提供统一的 API 层。以下参考文档可用:
Capa API 规范遵循社区标准,定义在 cloud-runtimes-jvm 仓库中。
Capa API 契约、SDK、运行时和云适配器分别发布。集成时应明确匹配版本,不要假设所有仓库共享同一个版本号。
| 组件 | 版本或状态 | 用途 |
|---|---|---|
| cloud-runtimes-jvm | 1.19.RELEASE | JVM API 契约和部分运行时 adapter |
| capa-java | 1.11.13.2.RELEASE | Java 富 SDK |
| capa-java-aws | 1.11.13.5.RELEASE | Capa Java 的 AWS SPI 模块 |
| cloud-runtimes-golang | 接口规范 | Go API 契约,不包含运行时实现 |
| cloud-runtimes-python | Alpha 源码 API | 修正后的制品发布前使用源码安装 |
| capa | 实验性 | 独立演进的 Go Sidecar/运行时 |
RELEASE 后缀版本升级前检查发布说明和源码差异。Java API 类型可从 cloud-runtimes-api 源码开始查阅;Java SDK 用法请参考 capa-java examples。
感谢您对Capa的支持!
Capa 基于 Apache 2.0 许可发布,遵循标准的 Github 开发流程。 本文档描述了如何使用 Github Issue 和 Pull Request 对Capa做出贡献。
范例:
源类的全限定名为 com.api.Matching
源文件路径 src/main/java/com/api/Matching.java
UT文件路径 src/test/java/com/api/MatchingTest.java
范例:
源方法名为 matching()
UT方法命名为 testMatching_Success()/testMatching_SuccessWhenResultGreaterThanZero()/testMatching_FailWhenThrowException()
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
本文档描述了如何为 Capa 文档库做出贡献。文档库使用 Markdown 语法编写。已发布到 capa-cloud/capa.io。
Capa 文档库使用 Hugo 的 Docsy 主题构建。
文件统一放在 content/ 目录下,其中中文文档存放于 content/zh ,英文文档存放于 content/en。
如果需要新增文档,需要按照目录结构新增文件夹和.md文件。

图片统一放在 content/images/ 目录下,其中图片目录结构与所引用的 md 文件的目录保持一致。需要选用清晰且与背景适配的图片。
共享图片位于 content/images 目录。嵌入图片时请使用指向具体文件的完整 raw URL。
例如,引入下图的图片(contribution_file.png),Markdown写法如下:

