From 0d3570e5c0215de60f2abb952b4995ecd8d3057f Mon Sep 17 00:00:00 2001 From: Kevin_T <596823919@qq.com> Date: Wed, 29 Dec 2021 18:28:10 +0800 Subject: [PATCH 01/13] feat: add plugin module --- .../capa/component/CapaRpcProperties.java | 70 ++++++++++++++++++ .../rxcloud/capa/component/http/CapaHttp.java | 1 + .../capa/component/http/CapaHttpBuilder.java | 4 +- .../capa/infrastructure/CapaClassLoader.java | 14 ++++ .../capa/infrastructure/CapaConstants.java | 8 +- .../capa/infrastructure/CapaProperties.java | 65 +++++++++-------- .../infrastructure/plugin/PluginLoader.java | 73 +++++++++++++++++++ .../infrastructure/plugin/PluginOrder.java | 25 +++++++ .../capa/infrastructure/plugin/Plugin.java | 22 ++++++ .../infrastructure/plugin/PluginImpl.java | 25 +++++++ .../plugin/PluginLoaderTest.java | 44 +++++++++++ ....rxcloud.capa.infrastructure.plugin.Plugin | 1 + .../spi/configstore/CapaConfigStoreSpi.java | 4 +- .../spi/http/config/CapaSpiProperties.java | 7 +- .../telemetry/CapaContextAsyncWrapperSpi.java | 1 - .../spi/telemetry/CapaDoubleHistogramSpi.java | 11 +++ .../spi/telemetry/CapaLongHistogramSpi.java | 11 +++ .../capa/spi/telemetry/CapaMeterSpi.java | 8 ++ .../spi/telemetry/CapaMetricsExporterSpi.java | 7 +- .../spi/telemetry/CapaReadWriteSpanSpi.java | 8 ++ .../spi/telemetry/CapaSpanBuilderSpi.java | 9 +++ .../spi/telemetry/CapaTracerBuilderSpi.java | 6 ++ .../capa/spi/telemetry/CapaTracerSpi.java | 8 ++ .../telemetry/ContextPropagatorLoaderSpi.java | 1 - .../capa/rpc/CapaRpcClientBuilder.java | 4 +- 25 files changed, 391 insertions(+), 46 deletions(-) create mode 100644 sdk-component/src/main/java/group/rxcloud/capa/component/CapaRpcProperties.java create mode 100644 sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginLoader.java create mode 100644 sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginOrder.java create mode 100644 sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/Plugin.java create mode 100644 sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginImpl.java create mode 100644 sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java create mode 100644 sdk-infrastructure/src/test/resources/META-INF/services/group.rxcloud.capa.infrastructure.plugin.Plugin diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/CapaRpcProperties.java b/sdk-component/src/main/java/group/rxcloud/capa/component/CapaRpcProperties.java new file mode 100644 index 0000000..9e1e1d8 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/CapaRpcProperties.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.component; + +import group.rxcloud.capa.infrastructure.CapaProperties; + +import java.util.Properties; + +/** + * Capa rpc component common properties. + */ +public interface CapaRpcProperties { + + abstract class Settings { + + /** + * Determines if Capa client will use HTTP or Other client. + */ + public static String API_PROTOCOL; + + /** + * Capa's timeout in seconds for HTTP client reads. + */ + public static Integer HTTP_CLIENT_READ_TIMEOUT_SECONDS; + + /** + * Capa's default use of HTTP. + */ + private static final String DEFAULT_API_PROTOCOL = "HTTP"; + + /** + * Capa's default timeout in seconds for HTTP client reads. + */ + private static final Integer DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS = 60; + + static { + Properties properties = CapaProperties.COMPONENT_PROPERTIES_SUPPLIER.apply("rpc"); + + API_PROTOCOL = properties.getProperty("API_PROTOCOL", DEFAULT_API_PROTOCOL); + + String httpClientReadTimeoutSeconds = properties.getProperty("HTTP_CLIENT_READ_TIMEOUT_SECONDS", String.valueOf(DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS)); + HTTP_CLIENT_READ_TIMEOUT_SECONDS = Integer.valueOf(httpClientReadTimeoutSeconds); + } + + public static String getApiProtocol() { + return API_PROTOCOL; + } + + public static Integer getHttpClientReadTimeoutSeconds() { + return HTTP_CLIENT_READ_TIMEOUT_SECONDS; + } + + private Settings() { + } + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttp.java b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttp.java index f43a0aa..d9b2224 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttp.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttp.java @@ -107,6 +107,7 @@ public Mono> invokeApi(String httpMethod, /** * Invokes an API that returns a {@code } payload. + * FIXME: expose {@code Mono}, not {@code CompletableFuture} * * @param The Type of the return. * @param httpMethod HTTP httpMethod. diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java index 087ceba..2aca826 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java @@ -17,8 +17,8 @@ package group.rxcloud.capa.component.http; +import group.rxcloud.capa.component.CapaRpcProperties; import group.rxcloud.capa.infrastructure.CapaClassLoader; -import group.rxcloud.capa.infrastructure.CapaProperties; import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; import okhttp3.OkHttpClient; @@ -96,7 +96,7 @@ private CapaHttp buildCapaHttp() { if (OK_HTTP_CLIENT.get() == null) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); // read timeout property - Duration readTimeout = Duration.ofSeconds(CapaProperties.HTTP_CLIENT_READ_TIMEOUT_SECONDS.get()); + Duration readTimeout = Duration.ofSeconds(CapaRpcProperties.Settings.getHttpClientReadTimeoutSeconds()); builder.readTimeout(readTimeout); OkHttpClient okHttpClient = builder.build(); OK_HTTP_CLIENT.set(okHttpClient); diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaClassLoader.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaClassLoader.java index 6429f40..3ca5700 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaClassLoader.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaClassLoader.java @@ -81,6 +81,20 @@ public static T loadInfrastructureClassObj(String infrastructureDomain, Clas return loadClassObj(implClassPath, parameterTypes, initargs); } + /** + * Load plugin class obj. + * + * @param the target class type + * @param superClazz the interface class type + * @return the target plugin class obj + */ + public static T loadPluginClassObj(Class superClazz) { + Object pluginImpl = CapaProperties.PLUGIN_PROPERTIES_SUPPLIER.apply(superClazz); + return (T) pluginImpl; + } + + // -- Private + private static T loadClassObj(String classPath, Class[] parameterTypes, Object[] initargs) { try { Class aClass = (Class) Class.forName(classPath); diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java index 752ea46..0fa36e1 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java @@ -26,14 +26,14 @@ interface CapaConstants { */ interface Properties { - /** - * The {@code infrastructure} properties prefix. - */ - String CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX = "/capa-infrastructure-"; /** * The {@code component} properties prefix. */ String CAPA_COMPONENT_PROPERTIES_PREFIX = "/capa-component-"; + /** + * The {@code infrastructure} properties prefix. + */ + String CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX = "/capa-infrastructure-"; /** * The properties suffix. diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java index c2a4243..17ad9d8 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java @@ -27,18 +27,20 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Properties; +import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.function.Supplier; import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_COMPONENT_PROPERTIES_PREFIX; import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX; import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_PROPERTIES_SUFFIX; import static group.rxcloud.capa.infrastructure.InnerModule.FILE_CACHE_MAP; import static group.rxcloud.capa.infrastructure.InnerModule.loadCapaConfig; +import static group.rxcloud.capa.infrastructure.InnerModule.loadCapaFileByJavaSpi; import static group.rxcloud.capa.infrastructure.InnerModule.loadCapaProperties; /** @@ -47,25 +49,16 @@ public abstract class CapaProperties { /** - * Capa's default use of HTTP. - */ - private static final Supplier DEFAULT_API_PROTOCOL = () -> "HTTP"; - - /** - * Determines if Capa client will use HTTP or Other client. - */ - public static final Supplier API_PROTOCOL = DEFAULT_API_PROTOCOL; - - /** - * Capa's default timeout in seconds for HTTP client reads. - */ - private static final Integer DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS = 60; - - /** - * Capa's timeout in seconds for HTTP client reads. + * Capa's component properties supplier. */ - public static final Supplier HTTP_CLIENT_READ_TIMEOUT_SECONDS - = () -> DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS; + public static final Function COMPONENT_PROPERTIES_SUPPLIER + = (componentDomain) -> (Properties) FILE_CACHE_MAP.computeIfAbsent(componentDomain, + s -> { + final String fileName = CAPA_COMPONENT_PROPERTIES_PREFIX + + componentDomain.toLowerCase() + + CAPA_PROPERTIES_SUFFIX; + return loadCapaProperties(fileName); + }); /** * Capa's infrastructure properties supplier. @@ -80,16 +73,11 @@ public abstract class CapaProperties { }); /** - * Capa's component properties supplier. + * Capa's plugin properties supplier. */ - public static final Function COMPONENT_PROPERTIES_SUPPLIER - = (componentDomain) -> (Properties) FILE_CACHE_MAP.computeIfAbsent(componentDomain, - s -> { - final String fileName = CAPA_COMPONENT_PROPERTIES_PREFIX - + componentDomain.toLowerCase() - + CAPA_PROPERTIES_SUFFIX; - return loadCapaProperties(fileName); - }); + public static final Function PLUGIN_PROPERTIES_SUPPLIER + = (clazz) -> FILE_CACHE_MAP.computeIfAbsent(clazz.getName(), + s -> loadCapaFileByJavaSpi(clazz)); /** * Capa's config file supplier. @@ -118,19 +106,32 @@ static Properties loadCapaProperties(final String fileName) { properties.load(inputStreamReader); return properties; } catch (IOException e) { - throw new IllegalArgumentException(fileName + " file not found."); + throw new IllegalArgumentException(fileName + " file not found.", e); } } static T loadCapaConfig(final String fileName, Class configClazz) { Objects.requireNonNull(fileName, "fileName not found."); - try (InputStream in = configClazz.getResourceAsStream(fileName)) { + try (InputStream in = CapaProperties.class.getResourceAsStream(fileName)) { InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); return OBJECT_MAPPER.readValue(inputStreamReader, configClazz); } catch (JsonParseException | JsonMappingException e) { - throw new IllegalArgumentException(fileName + " file not load."); + throw new IllegalArgumentException(fileName + " file not load.", e); } catch (IOException e) { - throw new IllegalArgumentException(fileName + " file not found."); + throw new IllegalArgumentException(fileName + " file not found.", e); + } + } + + static T loadCapaFileByJavaSpi(Class configClazz) { + try { + ServiceLoader loader = ServiceLoader.load(configClazz); + Iterator iterator = loader.iterator(); + if (!iterator.hasNext()) { + return null; + } + return iterator.next(); + } catch (Exception e) { + throw new IllegalArgumentException(configClazz.getName() + " spi file not found.", e); } } } diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginLoader.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginLoader.java new file mode 100644 index 0000000..de783be --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginLoader.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.infrastructure.plugin; + +import group.rxcloud.capa.infrastructure.CapaClassLoader; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +/** + * The Plugin SPI loader. + */ +public final class PluginLoader { + + private static final Map pluginImplCache; + + static { + pluginImplCache = new ConcurrentHashMap<>(); + } + + public static Map getPluginImplCache() { + return pluginImplCache; + } + + /** + * Load plugin impl by java spi. + * + * @param the plugin interface type + * @param pluginSuperClazz the plugin interface class + * @return the optional of plugin impl + */ + public static Optional loadPluginImpl(Class pluginSuperClazz) { + Object o = pluginImplCache.computeIfAbsent(pluginSuperClazz, + aClass -> CapaClassLoader.loadPluginClassObj(pluginSuperClazz)); + return Optional.ofNullable((T) o); + } + + /** + * Load plugin impl by java spi. + * + * @param the plugin interface type + * @param pluginSuperClazz the plugin interface class + * @param defaultPluginObj the default plugin obj + * @return the plugin impl + */ + public static T loadPluginImpl(Class pluginSuperClazz, Supplier defaultPluginObj) { + Object o = pluginImplCache.computeIfAbsent(pluginSuperClazz, + aClass -> { + T pluginClassObj = CapaClassLoader.loadPluginClassObj(pluginSuperClazz); + if (pluginClassObj != null) { + return pluginClassObj; + } + return defaultPluginObj.get(); + }); + return (T) o; + } +} diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginOrder.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginOrder.java new file mode 100644 index 0000000..958dba6 --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/plugin/PluginOrder.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.infrastructure.plugin; + +/** + * TODO: 2021/12/29 currently only support one plugin. + */ +public @interface PluginOrder { + + int order() default 0; +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/Plugin.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/Plugin.java new file mode 100644 index 0000000..c2c38bf --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/Plugin.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.infrastructure.plugin; + +public interface Plugin { + + String sayHello(); +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginImpl.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginImpl.java new file mode 100644 index 0000000..87c2f7d --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginImpl.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.infrastructure.plugin; + +public class PluginImpl implements Plugin { + + @Override + public String sayHello() { + return "hello"; + } +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java new file mode 100644 index 0000000..2ab9dba --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.infrastructure.plugin; + +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class PluginLoaderTest { + + @Test + public void loadPluginImpl_spi() { + Optional pluginOp = PluginLoader.loadPluginImpl(Plugin.class); + Plugin plugin = pluginOp.get(); + assertNotEquals(plugin.sayHello(), "hello"); + } + + @Test + public void loadPluginImpl_default() { + Plugin plugin = PluginLoader.loadPluginImpl(Plugin.class, () -> new Plugin() { + @Override + public String sayHello() { + return "hhh"; + } + }); + assertNotEquals(plugin.sayHello(), "hello"); + } +} \ No newline at end of file diff --git a/sdk-infrastructure/src/test/resources/META-INF/services/group.rxcloud.capa.infrastructure.plugin.Plugin b/sdk-infrastructure/src/test/resources/META-INF/services/group.rxcloud.capa.infrastructure.plugin.Plugin new file mode 100644 index 0000000..7ce97bc --- /dev/null +++ b/sdk-infrastructure/src/test/resources/META-INF/services/group.rxcloud.capa.infrastructure.plugin.Plugin @@ -0,0 +1 @@ +group.rxcloud.capa.infrastructure.plugin.PluginImpl \ No newline at end of file diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpi.java index 09901ae..14c2506 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpi.java @@ -50,7 +50,7 @@ public CapaConfigStoreSpi(CapaObjectSerializer objectSerializer) { @Override public Mono>> get(GetRequest getRequest, TypeRef type) { if (logger.isDebugEnabled()) { - logger.debug("[CapaConfigStoreSpi] get config request[{}]", getRequest); + logger.debug("[Capa.Config] [CapaConfigStoreSpi] get config request[{}]", getRequest); } final String appId = getRequest.getAppId(); final String group = getRequest.getGroup(); @@ -84,7 +84,7 @@ protected abstract Mono>> doGet(String appId, @Override public Flux> subscribe(SubscribeReq subscribeReq, TypeRef type) { if (logger.isDebugEnabled()) { - logger.debug("[CapaConfigStoreSpi] subscribe config request[{}]", subscribeReq); + logger.debug("[Capa.Config] [CapaConfigStoreSpi] subscribe config request[{}]", subscribeReq); } final String appId = subscribeReq.getAppId(); final String group = subscribeReq.getGroup(); diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/config/CapaSpiProperties.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/config/CapaSpiProperties.java index e40d720..5a1550f 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/config/CapaSpiProperties.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/config/CapaSpiProperties.java @@ -23,6 +23,11 @@ */ public abstract class CapaSpiProperties { + /** + * Static lock object. + */ + private static final Object LOCK = new Object(); + private static volatile CapaSpiOptionsLoader instance; /** @@ -32,7 +37,7 @@ public abstract class CapaSpiProperties { */ public static CapaSpiOptionsLoader getSpiOptionsLoader() { if (instance == null) { - synchronized (CapaSpiProperties.class) { + synchronized (LOCK) { if (instance == null) { instance = CapaClassLoader.loadComponentClassObj("rpc-common", CapaSpiOptionsLoader.class); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java index 8062b67..55cf4c4 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java @@ -22,5 +22,4 @@ * SPI Capa context async wrapper. */ public abstract class CapaContextAsyncWrapperSpi implements CapaContextAsyncWrapper { - } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaDoubleHistogramSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaDoubleHistogramSpi.java index f0754d3..80299b5 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaDoubleHistogramSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaDoubleHistogramSpi.java @@ -19,9 +19,20 @@ import group.rxcloud.capa.component.telemetry.metrics.CapaDoubleHistogram; /** + * The Capa double histogram spi. */ public abstract class CapaDoubleHistogramSpi extends CapaDoubleHistogram { + /** + * Instantiates a new Capa double histogram spi. + * + * @param meterName the meter name + * @param schemaUrl the schema url + * @param version the version + * @param name the name + * @param description the description + * @param unit the unit + */ public CapaDoubleHistogramSpi(String meterName, String schemaUrl, String version, String name, String description, String unit) { super(meterName, schemaUrl, version, name, description, unit); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaLongHistogramSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaLongHistogramSpi.java index a07f545..0beb1f8 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaLongHistogramSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaLongHistogramSpi.java @@ -19,9 +19,20 @@ import group.rxcloud.capa.component.telemetry.metrics.CapaLongHistogram; /** + * The Capa long histogram spi. */ public abstract class CapaLongHistogramSpi extends CapaLongHistogram { + /** + * Instantiates a new Capa long histogram spi. + * + * @param meterName the meter name + * @param schemaUrl the schema url + * @param version the version + * @param name the name + * @param description the description + * @param unit the unit + */ public CapaLongHistogramSpi(String meterName, String schemaUrl, String version, String name, String description, String unit) { super(meterName, schemaUrl, version, name, description, unit); diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMeterSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMeterSpi.java index 7f31300..7731f92 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMeterSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMeterSpi.java @@ -24,6 +24,14 @@ */ public abstract class CapaMeterSpi extends CapaMeter { + /** + * Instantiates a new Capa meter spi. + * + * @param meterName the meter name + * @param schemaUrl the schema url + * @param version the version + * @param meter the meter + */ public CapaMeterSpi(String meterName, String schemaUrl, String version, Meter meter) { super(meterName, schemaUrl, version, meter); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMetricsExporterSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMetricsExporterSpi.java index a0fb3a7..f429078 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMetricsExporterSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaMetricsExporterSpi.java @@ -22,10 +22,15 @@ import java.util.function.Supplier; /** - * + * The Capa metrics exporter spi. */ public abstract class CapaMetricsExporterSpi extends CapaMetricsExporter { + /** + * Instantiates a new Capa metrics exporter spi. + * + * @param samplerConfig the sampler config + */ public CapaMetricsExporterSpi(Supplier samplerConfig) { super(samplerConfig); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java index a317306..08cd88a 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java @@ -24,6 +24,14 @@ */ public abstract class CapaReadWriteSpanSpi extends CapaReadWriteSpan { + /** + * Instantiates a new Capa read write span spi. + * + * @param tracerName the tracer name + * @param version the version + * @param schemaUrl the schema url + * @param span the span + */ public CapaReadWriteSpanSpi(String tracerName, String version, String schemaUrl, ReadWriteSpan span) { super(tracerName, version, schemaUrl, span); diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java index f9c3686..5966405 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java @@ -24,6 +24,15 @@ */ public abstract class CapaSpanBuilderSpi extends CapaSpanBuilder { + /** + * Instantiates a new Capa span builder spi. + * + * @param tracerName the tracer name + * @param version the version + * @param schemaUrl the schema url + * @param spanName the span name + * @param spanBuilder the span builder + */ public CapaSpanBuilderSpi(String tracerName, String version, String schemaUrl, String spanName, SpanBuilder spanBuilder) { super(tracerName, version, schemaUrl, spanName, spanBuilder); diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java index 3599480..672184b 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java @@ -24,6 +24,12 @@ */ public abstract class CapaTracerBuilderSpi extends CapaTracerBuilder { + /** + * Instantiates a new Capa tracer builder spi. + * + * @param tracerName the tracer name + * @param builder the builder + */ public CapaTracerBuilderSpi(String tracerName, TracerBuilder builder) { super(tracerName, builder); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java index 53239a5..8cb2872 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java @@ -24,6 +24,14 @@ */ public abstract class CapaTracerSpi extends CapaTracer { + /** + * Instantiates a new Capa tracer spi. + * + * @param tracerName the tracer name + * @param version the version + * @param schemaUrl the schema url + * @param tracer the tracer + */ public CapaTracerSpi(String tracerName, String version, String schemaUrl, Tracer tracer) { super(tracerName, version, schemaUrl, tracer); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java index 148165d..65f82fe 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java @@ -23,5 +23,4 @@ * SPI context propagator loader. */ public abstract class ContextPropagatorLoaderSpi implements ContextPropagatorLoader { - } diff --git a/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientBuilder.java b/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientBuilder.java index e3ef4f0..91ecce5 100644 --- a/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientBuilder.java +++ b/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientBuilder.java @@ -17,8 +17,8 @@ package group.rxcloud.capa.rpc; +import group.rxcloud.capa.component.CapaRpcProperties; import group.rxcloud.capa.component.http.CapaHttpBuilder; -import group.rxcloud.capa.infrastructure.CapaProperties; import java.util.function.Supplier; @@ -55,7 +55,7 @@ public CapaRpcClientBuilder(Supplier capaHttpBuilderSupplier) { * Creates a constructor for {@link CapaRpcClient}. */ public CapaRpcClientBuilder(CapaHttpBuilder httpBuilder) { - this.apiProtocol = CapaApiProtocol.parseProtocol(CapaProperties.API_PROTOCOL.get()); + this.apiProtocol = CapaApiProtocol.parseProtocol(CapaRpcProperties.Settings.getApiProtocol()); this.httpBuilder = httpBuilder; } From 16d4803a7c3865ddd0955ae7488335f2972cdbd8 Mon Sep 17 00:00:00 2001 From: Kevin_T <596823919@qq.com> Date: Wed, 29 Dec 2021 18:38:20 +0800 Subject: [PATCH 02/13] chore: fix pipeline --- .../capa/component/CapaRpcPropertiesTest.java | 35 +++++++++++++++++++ .../infrastructure/CapaPropertiesTest.java | 12 ------- .../plugin/PluginLoaderTest.java | 6 ++-- 3 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 sdk-component/src/test/java/group/rxcloud/capa/component/CapaRpcPropertiesTest.java diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/CapaRpcPropertiesTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/CapaRpcPropertiesTest.java new file mode 100644 index 0000000..9df292b --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/CapaRpcPropertiesTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package group.rxcloud.capa.component; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CapaRpcPropertiesTest { + + @Test + public void testGetApiProtocol_Success() { + String apiProtocol = CapaRpcProperties.Settings.getApiProtocol(); + Assertions.assertEquals("HTTP", apiProtocol); + } + + @Test + public void testGetHttpClientReadTimeoutSeconds_Success() { + Integer httpClientReadTimeoutSeconds = CapaRpcProperties.Settings.getHttpClientReadTimeoutSeconds(); + Assertions.assertEquals(60, httpClientReadTimeoutSeconds.intValue()); + } +} \ No newline at end of file diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/CapaPropertiesTest.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/CapaPropertiesTest.java index 1410b65..11c803c 100644 --- a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/CapaPropertiesTest.java +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/CapaPropertiesTest.java @@ -23,18 +23,6 @@ public class CapaPropertiesTest { - @Test - public void testGetApiProtocol_Success() { - String apiProtocol = CapaProperties.API_PROTOCOL.get(); - Assertions.assertEquals("HTTP", apiProtocol); - } - - @Test - public void testGetHttpClientReadTimeoutSeconds_Success() { - Integer httpClientReadTimeoutSeconds = CapaProperties.HTTP_CLIENT_READ_TIMEOUT_SECONDS.get(); - Assertions.assertEquals(60, httpClientReadTimeoutSeconds.intValue()); - } - @Test public void testGetComponentProperties_Success() { Properties properties = CapaProperties.COMPONENT_PROPERTIES_SUPPLIER.apply("rpc"); diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java index 2ab9dba..9855799 100644 --- a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/plugin/PluginLoaderTest.java @@ -20,7 +20,7 @@ import java.util.Optional; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PluginLoaderTest { @@ -28,7 +28,7 @@ public class PluginLoaderTest { public void loadPluginImpl_spi() { Optional pluginOp = PluginLoader.loadPluginImpl(Plugin.class); Plugin plugin = pluginOp.get(); - assertNotEquals(plugin.sayHello(), "hello"); + assertEquals(plugin.sayHello(), "hello"); } @Test @@ -39,6 +39,6 @@ public String sayHello() { return "hhh"; } }); - assertNotEquals(plugin.sayHello(), "hello"); + assertEquals(plugin.sayHello(), "hello"); } } \ No newline at end of file From 23890b83445f95dbe543f29db54f9abc445b5dd3 Mon Sep 17 00:00:00 2001 From: chenyijiang Date: Thu, 30 Dec 2021 15:16:04 +0800 Subject: [PATCH 03/13] Remove the dependency of configuration during the initialization of telemetry client. --- .../component/telemetry/SamplerConfig.java | 59 ++++++++++++++----- .../telemetry/SamplerConfigTest.java | 11 ++++ .../capa/infrastructure/utils/SpiUtils.java | 39 ------------ .../infrastructure/utils/SpiUtilsTest.java | 25 -------- 4 files changed, 55 insertions(+), 79 deletions(-) diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java index ea0b1da..b1b3414 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java @@ -18,12 +18,16 @@ import group.rxcloud.capa.component.CapaTelemetryProperties; import group.rxcloud.capa.component.telemetry.metrics.CapaMeterProviderBuilder; +import group.rxcloud.capa.infrastructure.hook.ConfigurationHooks; import group.rxcloud.capa.infrastructure.hook.MergedPropertiesConfig; import group.rxcloud.capa.infrastructure.hook.Mixer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; /** @@ -39,16 +43,42 @@ public class SamplerConfig implements Serializable { setMetricsEnable(true); }}; - public static final transient SamplerConfig CONFIG = new SamplerConfig(); + public static final transient AtomicReference REMOTE_CONFIG = new AtomicReference<>(); + + private static final int MAX_REMOTE_INIT_RETRY = 5; + + private static final transient AtomicInteger CONFIG_INIT = new AtomicInteger(0); private static final long serialVersionUID = -2113523925814197551L; private static final transient Logger log = LoggerFactory.getLogger(CapaMeterProviderBuilder.class); - public static transient Supplier DEFAULT_SUPPLIER = () -> CONFIG; + public static final transient Supplier DEFAULT_SUPPLIER = () -> { + if (CONFIG_INIT.get() < MAX_REMOTE_INIT_RETRY) { + synchronized (CONFIG_INIT) { + if (CONFIG_INIT.getAndIncrement() <= MAX_REMOTE_INIT_RETRY) { + if (tryInitRemoteConfig()) { + CONFIG_INIT.set(MAX_REMOTE_INIT_RETRY); + } + } + } + } + + SamplerConfig config = REMOTE_CONFIG.get(); + if (config == null) { + config = DEFAULT_CONFIG; + } + return config; + }; + + private Boolean metricsEnable; + + private Boolean traceEnable; - static { - Mixer.configurationHooksNullable().ifPresent(hooks -> { + private static boolean tryInitRemoteConfig() { + Optional hooksOpt = Mixer.configurationHooksNullable(); + if (hooksOpt.isPresent()) { + ConfigurationHooks hooks = hooksOpt.get(); String fileName = "capa-component-telemetry-sampling.properties"; try { // TODO: 2021/12/3 Move this to SPI module. @@ -63,30 +93,29 @@ public class SamplerConfig implements Serializable { @Override public Boolean isMetricsEnable() { return !config.containsKey(metricKey) || Boolean.TRUE.toString() - .equalsIgnoreCase(config.get(metricKey)); + .equalsIgnoreCase(config.get(metricKey)); } @Override public Boolean isTraceEnable() { return !config.containsKey(traceKey) || Boolean.TRUE.toString() - .equalsIgnoreCase(config.get(traceKey)); + .equalsIgnoreCase(config.get(traceKey)); } }; - DEFAULT_SUPPLIER = () -> dynamicConfig; + REMOTE_CONFIG.set(dynamicConfig); + + return true; } catch (Throwable throwable) { - log.warn("Fail to load global telemetry config. Dynamic global config is disabled for capa telemetry.", + log.info("Fail to load global telemetry config. Dynamic global config is disabled for capa telemetry.", throwable); } - }); + } + return false; } - private Boolean metricsEnable; - - private Boolean traceEnable; - public Boolean isMetricsEnable() { - return metricsEnable == null ? DEFAULT_CONFIG.metricsEnable : metricsEnable; + return metricsEnable == null ? DEFAULT_SUPPLIER.get().metricsEnable : metricsEnable; } public void setMetricsEnable(boolean metricsEnable) { @@ -94,7 +123,7 @@ public void setMetricsEnable(boolean metricsEnable) { } public Boolean isTraceEnable() { - return traceEnable == null ? DEFAULT_CONFIG.traceEnable : traceEnable; + return traceEnable == null ? DEFAULT_SUPPLIER.get().traceEnable : traceEnable; } public void setTraceEnable(boolean traceEnable) { diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java index c8c4a59..5e4120b 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java @@ -19,11 +19,14 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * @author: chenyijiang * @date: 2021/12/2 12:33 */ + public class SamplerConfigTest { @Test @@ -35,4 +38,12 @@ public void isMetricsEnable() { public void isTraceEnable() { assertFalse(SamplerConfig.DEFAULT_SUPPLIER.get().isTraceEnable()); } + @Test + public void configurationWeakDependency() { + for (int i = 0; i < 6; i++) { + SamplerConfig config = SamplerConfig.DEFAULT_SUPPLIER.get(); + assertNotNull(config); + assertNotEquals(SamplerConfig.DEFAULT_CONFIG, config); + } + } } \ No newline at end of file diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java index 7096f6a..0bf4b12 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java @@ -21,8 +21,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import group.rxcloud.capa.infrastructure.CapaProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -49,8 +47,6 @@ public final class SpiUtils { private static final Map CACHE = new ConcurrentHashMap<>(); - private static final Logger log = LoggerFactory.getLogger(SpiUtils.class); - private SpiUtils() { } @@ -59,46 +55,12 @@ public static T loadConfigNullable(String path, Class configType) { if (in != null) { InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); return OBJECT_MAPPER.readValue(inputStreamReader, configType); - } else { - log.warn(path + " file not found."); - } - } catch (IOException e) { - log.warn(path + " config file not found.", e); - } - return null; - } - - public static Properties loadPropertiesNullable(String path) { - try (InputStream in = SpiUtils.class.getResourceAsStream(path)) { - if (in != null) { - InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); - Properties properties = new Properties(); - properties.load(inputStreamReader); - return properties; - } else { - log.warn(path + " file not found."); } } catch (IOException e) { - log.warn(path + " file not found.", e); } return null; } - public static Properties loadProperties(String path) { - try (InputStream in = SpiUtils.class.getResourceAsStream(path)) { - if (in != null) { - InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); - Properties properties = new Properties(); - properties.load(inputStreamReader); - return properties; - } else { - throw new IllegalArgumentException(path + " file not found."); - } - } catch (IOException e) { - throw new IllegalArgumentException(path + " file not found.", e); - } - } - @Nullable public static T loadFromSpiComponentFileNullable(Class type, String fileSuffix) { return loadFromSpiComponentFileNullable(type, null, null, fileSuffix, false); @@ -115,7 +77,6 @@ public static T loadFromSpiComponentFileNullable(Class type, Class[] argT } return null; } catch (Throwable e) { - log.info("Fail to load " + type.getName() + " instance from spi config file."); } return null; } diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java index ddefc30..9e0ab08 100644 --- a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test; import java.util.List; -import java.util.Properties; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -39,30 +38,6 @@ public void loadConfigNullable() { assertNull(SpiUtils.loadConfigNullable("/config.json", Integer.class)); } - @Test - public void loadPropertiesNullable() { - Properties properties = SpiUtils.loadPropertiesNullable("/config.properties"); - assertEquals("aaa", properties.getProperty("str")); - - assertNull(SpiUtils.loadPropertiesNullable("lalala")); - } - - @Test - public void loadProperties() { - Properties properties = SpiUtils.loadProperties("/config.properties"); - assertEquals("aaa", properties.getProperty("str")); - } - - @Test - public void loadPropertiesFail() { - Throwable t = null; - try { - Properties properties = SpiUtils.loadProperties("aaaa"); - } catch (Throwable throwable) { - t = throwable; - } - assertNotNull(t); - } @Test public void loadFromSpiComponentFileNullable() { MyInterface myInterface = SpiUtils.loadFromSpiComponentFileNullable(MyInterface.class, "test"); From 6f9622330cf04de465f18050c3efbb9b9157ba1b Mon Sep 17 00:00:00 2001 From: chenyijiang Date: Thu, 30 Dec 2021 15:51:19 +0800 Subject: [PATCH 04/13] Upgrade version. --- examples/pom.xml | 2 +- pom.xml | 2 +- sdk-component/pom.xml | 2 +- sdk-infrastructure/pom.xml | 2 +- sdk-spi-demo/pom.xml | 2 +- sdk-spi/pom.xml | 2 +- sdk-springboot/pom.xml | 2 +- sdk/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index d548ea9..ad76475 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-examples diff --git a/pom.xml b/pom.xml index dbea5fe..1e20552 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent pom - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk-parent SDK for Capa. https://github.com/reactivegroup diff --git a/sdk-component/pom.xml b/sdk-component/pom.xml index 75357b3..ee3851f 100644 --- a/sdk-component/pom.xml +++ b/sdk-component/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk-component diff --git a/sdk-infrastructure/pom.xml b/sdk-infrastructure/pom.xml index 0399299..008a294 100644 --- a/sdk-infrastructure/pom.xml +++ b/sdk-infrastructure/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk-infrastructure diff --git a/sdk-spi-demo/pom.xml b/sdk-spi-demo/pom.xml index 0b66c70..5a65709 100644 --- a/sdk-spi-demo/pom.xml +++ b/sdk-spi-demo/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk-spi-demo diff --git a/sdk-spi/pom.xml b/sdk-spi/pom.xml index 27f0352..cd52642 100644 --- a/sdk-spi/pom.xml +++ b/sdk-spi/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk-spi diff --git a/sdk-springboot/pom.xml b/sdk-springboot/pom.xml index 4d65c37..921629f 100644 --- a/sdk-springboot/pom.xml +++ b/sdk-springboot/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.11.13.RELEASE + 1.11.13.2.RELEASE sdk-springboot diff --git a/sdk/pom.xml b/sdk/pom.xml index 23dbbd5..7bfd1b4 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent - 1.11.13.RELEASE + 1.11.13.2.RELEASE capa-sdk From 36d3549cb445c4de4489bbf77f0d3de4f681a296 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:17:32 +0000 Subject: [PATCH 05/13] chore(deps): bump log4j-core from 2.17.0 to 2.17.1 in /sdk-spi-demo Bumps log4j-core from 2.17.0 to 2.17.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- sdk-spi-demo/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-spi-demo/pom.xml b/sdk-spi-demo/pom.xml index 5a65709..db60b90 100644 --- a/sdk-spi-demo/pom.xml +++ b/sdk-spi-demo/pom.xml @@ -31,7 +31,7 @@ capa-sdk-spi-demo - 2.17.0 + 2.17.1 1.2.10 From 60aac7b27d50d550d40133740ff728ad8f8b3c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:17:50 +0000 Subject: [PATCH 06/13] chore(deps): bump log4j-api from 2.17.0 to 2.17.1 in /examples Bumps log4j-api from 2.17.0 to 2.17.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-api dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- examples/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pom.xml b/examples/pom.xml index ad76475..e07c6e9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -31,7 +31,7 @@ capa-sdk-examples - 2.17.0 + 2.17.1 1.2.10 From a5713926708dc5aa75875d4739a728372dcd00e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:23:04 +0000 Subject: [PATCH 07/13] chore(deps): bump log4j-core from 2.17.0 to 2.17.1 in /sdk-component Bumps log4j-core from 2.17.0 to 2.17.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- sdk-component/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-component/pom.xml b/sdk-component/pom.xml index ee3851f..120a79b 100644 --- a/sdk-component/pom.xml +++ b/sdk-component/pom.xml @@ -33,7 +33,7 @@ 4.9.1 1.4.10 - 2.17.0 + 2.17.1 1.2.10 From decdc09448cae6548a0437c74c1be2cedaec7ac1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:23:05 +0000 Subject: [PATCH 08/13] chore(deps): bump log4j-core from 2.17.0 to 2.17.1 in /sdk-spi Bumps log4j-core from 2.17.0 to 2.17.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- sdk-spi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-spi/pom.xml b/sdk-spi/pom.xml index cd52642..2537bf6 100644 --- a/sdk-spi/pom.xml +++ b/sdk-spi/pom.xml @@ -31,7 +31,7 @@ capa-sdk-spi - 2.17.0 + 2.17.1 1.2.10 From 3fb722efbaaa1d8602c1eb06350ca0ba0e8d60f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 Jan 2022 15:23:09 +0000 Subject: [PATCH 09/13] chore(deps): bump log4j-core from 2.17.0 to 2.17.1 in /examples Bumps log4j-core from 2.17.0 to 2.17.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- examples/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pom.xml b/examples/pom.xml index ad76475..e07c6e9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -31,7 +31,7 @@ capa-sdk-examples - 2.17.0 + 2.17.1 1.2.10 From c7930d0d2cf1a07b9ac8455f0202564e7f63f654 Mon Sep 17 00:00:00 2001 From: Kevin_T <596823919@qq.com> Date: Thu, 27 Jan 2022 16:31:23 +0800 Subject: [PATCH 10/13] chore: reformat --- .../component/telemetry/SamplerConfig.java | 78 +------------ .../telemetry/SamplerConfigTest.java | 11 +- .../hook/MergedPropertiesConfig.java | 110 ------------------ 3 files changed, 7 insertions(+), 192 deletions(-) delete mode 100644 sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/MergedPropertiesConfig.java diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java index b1b3414..60df1ac 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java @@ -16,18 +16,7 @@ */ package group.rxcloud.capa.component.telemetry; -import group.rxcloud.capa.component.CapaTelemetryProperties; -import group.rxcloud.capa.component.telemetry.metrics.CapaMeterProviderBuilder; -import group.rxcloud.capa.infrastructure.hook.ConfigurationHooks; -import group.rxcloud.capa.infrastructure.hook.MergedPropertiesConfig; -import group.rxcloud.capa.infrastructure.hook.Mixer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.Serializable; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; /** @@ -43,77 +32,12 @@ public class SamplerConfig implements Serializable { setMetricsEnable(true); }}; - public static final transient AtomicReference REMOTE_CONFIG = new AtomicReference<>(); - - private static final int MAX_REMOTE_INIT_RETRY = 5; - - private static final transient AtomicInteger CONFIG_INIT = new AtomicInteger(0); - - private static final long serialVersionUID = -2113523925814197551L; - - private static final transient Logger log = LoggerFactory.getLogger(CapaMeterProviderBuilder.class); - - public static final transient Supplier DEFAULT_SUPPLIER = () -> { - if (CONFIG_INIT.get() < MAX_REMOTE_INIT_RETRY) { - synchronized (CONFIG_INIT) { - if (CONFIG_INIT.getAndIncrement() <= MAX_REMOTE_INIT_RETRY) { - if (tryInitRemoteConfig()) { - CONFIG_INIT.set(MAX_REMOTE_INIT_RETRY); - } - } - } - } - - SamplerConfig config = REMOTE_CONFIG.get(); - if (config == null) { - config = DEFAULT_CONFIG; - } - return config; - }; + public static final transient Supplier DEFAULT_SUPPLIER = () -> DEFAULT_CONFIG; private Boolean metricsEnable; private Boolean traceEnable; - private static boolean tryInitRemoteConfig() { - Optional hooksOpt = Mixer.configurationHooksNullable(); - if (hooksOpt.isPresent()) { - ConfigurationHooks hooks = hooksOpt.get(); - String fileName = "capa-component-telemetry-sampling.properties"; - try { - // TODO: 2021/12/3 Move this to SPI module. - // TODO: 2021/12/3 And use Configuration extension api to get merged file. - MergedPropertiesConfig config = new MergedPropertiesConfig( - fileName, - hooks.defaultConfigurationAppId(), - CapaTelemetryProperties.Settings.getCenterConfigAppId()); - String metricKey = "metricsEnable"; - String traceKey = "traceEnable"; - SamplerConfig dynamicConfig = new SamplerConfig() { - @Override - public Boolean isMetricsEnable() { - return !config.containsKey(metricKey) || Boolean.TRUE.toString() - .equalsIgnoreCase(config.get(metricKey)); - } - - @Override - public Boolean isTraceEnable() { - return !config.containsKey(traceKey) || Boolean.TRUE.toString() - .equalsIgnoreCase(config.get(traceKey)); - } - }; - - REMOTE_CONFIG.set(dynamicConfig); - - return true; - } catch (Throwable throwable) { - log.info("Fail to load global telemetry config. Dynamic global config is disabled for capa telemetry.", - throwable); - } - } - return false; - } - public Boolean isMetricsEnable() { return metricsEnable == null ? DEFAULT_SUPPLIER.get().metricsEnable : metricsEnable; } diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java index 5e4120b..b36b505 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/SamplerConfigTest.java @@ -18,9 +18,9 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author: chenyijiang @@ -31,19 +31,20 @@ public class SamplerConfigTest { @Test public void isMetricsEnable() { - assertFalse(SamplerConfig.DEFAULT_SUPPLIER.get().isMetricsEnable()); + assertTrue(SamplerConfig.DEFAULT_SUPPLIER.get().isMetricsEnable()); } @Test public void isTraceEnable() { - assertFalse(SamplerConfig.DEFAULT_SUPPLIER.get().isTraceEnable()); + assertTrue(SamplerConfig.DEFAULT_SUPPLIER.get().isTraceEnable()); } + @Test public void configurationWeakDependency() { for (int i = 0; i < 6; i++) { SamplerConfig config = SamplerConfig.DEFAULT_SUPPLIER.get(); assertNotNull(config); - assertNotEquals(SamplerConfig.DEFAULT_CONFIG, config); + assertEquals(SamplerConfig.DEFAULT_CONFIG, config); } } } \ No newline at end of file diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/MergedPropertiesConfig.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/MergedPropertiesConfig.java deleted file mode 100644 index fce050e..0000000 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/MergedPropertiesConfig.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package group.rxcloud.capa.infrastructure.hook; - -import group.rxcloud.cloudruntimes.domain.core.configuration.SubConfigurationResp; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReferenceArray; - -/** - * Config provider to merge multiple properties file which takes the input order as their priority. - *

- * - * TODO: 2021/12/3 This should not in infrastructure layer. - * TODO: 2021/12/3 Use Configuration extension api to get merged file. - */ -@Deprecated -public class MergedPropertiesConfig { - - private static final Logger log = LoggerFactory.getLogger(MergedPropertiesConfig.class); - - private final String fileName; - - private final AtomicReferenceArray properties; - - private final Object lock = new Object(); - - private volatile Map merged; - - public MergedPropertiesConfig(String fileName, String... appIds) { - this.fileName = fileName; - properties = new AtomicReferenceArray<>(appIds.length); - merged = new HashMap<>(); - Mixer.configurationHooksNullable().ifPresent(hooks -> { - for (int i = 0; i < appIds.length; i++) { - try { - subscribeConfigurationByAppId(hooks, appIds[i], i); - } catch (Throwable throwable) { - log.warn("Fail to subscribe config for app id " + appIds[i] + ", index " + i, throwable); - } - - } - }); - } - - public boolean containsKey(String key) { - return merged.containsKey(key); - } - - public String get(String key) { - return merged.get(key); - } - - public Map getMerged() { - return merged; - } - - private void subscribeConfigurationByAppId(ConfigurationHooks configurationHooks, String appId, int index) { - String storeName = configurationHooks.registryStoreNames().get(0); - - Flux> configFlux = configurationHooks.subscribeConfiguration( - storeName, - appId, - Collections.singletonList(fileName), - null, - "", - "", - TypeRef.get(Map.class)); - - // FIXME: 2021/12/3 random callback? - configFlux.subscribe(resp -> { - synchronized (lock) { - if (!resp.getItems().isEmpty()) { - properties.set(index, resp.getItems().get(0).getContent()); - } else { - properties.set(index, null); - } - - Map merged = new HashMap<>(); - for (int i = 0; i < properties.length(); i++) { - Map item = properties.get(i); - if (item != null) { - item.forEach((k, v) -> merged.putIfAbsent(String.valueOf(k), String.valueOf(v))); - } - } - this.merged = merged; - } - }); - } -} From a27a00ee9a9e24c4a0b1593b6baeea7030e3ebf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 14:12:27 +0000 Subject: [PATCH 11/13] chore(deps): bump jackson-databind from 2.12.4 to 2.12.7.1 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.12.4 to 2.12.7.1. - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1e20552..37b559f 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ 3.3.22.RELEASE 1.7.21 1.39.0 - 2.12.4 + 2.12.7.1 1.9.0 1.9.0-alpha 5.3.1 From 65d0616157799518de571e04f9933221d63f731a Mon Sep 17 00:00:00 2001 From: Kevin_T <596823919@qq.com> Date: Mon, 19 Aug 2024 22:14:39 +0800 Subject: [PATCH 12/13] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7bc5757..d958ef5 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ With the help of the Capa project, your Java applications have the ability to ru [中文文档](./README_ZH.md) +[介绍文章](https://capa-cloud.github.io/capa.io/blog/2022/01/18/capa-mecha-sdk-of-cloud-application-api/) + ## Motivation ### Mecha architecture From 519179a2d2ccd433d9e08e7c491ebac72ec5f4c7 Mon Sep 17 00:00:00 2001 From: Kevin_T <596823919@qq.com> Date: Mon, 19 Aug 2024 22:15:08 +0800 Subject: [PATCH 13/13] Update README_ZH.md --- README_ZH.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README_ZH.md b/README_ZH.md index a13a2ae..7fa5ae5 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -6,6 +6,8 @@ 借助Capa体系,使你的Java应用在改动量较小的情况下,拥有跨云、混合云运行的能力。 +[介绍文章](https://capa-cloud.github.io/capa.io/blog/2022/01/18/capa-mecha-sdk-of-cloud-application-api/) + ## 动机 ### Mecha架构