From 7e7f751b8c67586ee8c531aa713ae75727fd0a88 Mon Sep 17 00:00:00 2001 From: xuqiu Date: Tue, 8 Aug 2023 16:01:19 +0800 Subject: [PATCH 01/64] =?UTF-8?q?1,=E4=BB=A3=E7=A0=81=E6=89=AB=E6=8F=8F?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=BF=BD=E7=95=A5dependabot=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=20(#1357)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 殷振南 --- .github/workflows/cloud_code_scan.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cloud_code_scan.yml b/.github/workflows/cloud_code_scan.yml index 7862061e8..3ee154447 100644 --- a/.github/workflows/cloud_code_scan.yml +++ b/.github/workflows/cloud_code_scan.yml @@ -1,6 +1,8 @@ name: Alipay Cloud Devops Codescan on: push: + branches-ignore: + - 'dependabot/**' jobs: deployment: From 666261d73df34070ea0706dcdf61461da4535023 Mon Sep 17 00:00:00 2001 From: xuqiu Date: Thu, 24 Aug 2023 15:22:23 +0800 Subject: [PATCH 02/64] code-scan support opensource check (#1359) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 殷振南 --- .github/workflows/cloud_code_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cloud_code_scan.yml b/.github/workflows/cloud_code_scan.yml index 3ee154447..c84cb387b 100644 --- a/.github/workflows/cloud_code_scan.yml +++ b/.github/workflows/cloud_code_scan.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: codeScan - uses: layotto/alipay-cloud-devops-codescan@0.1.20230724 + uses: layotto/alipay-cloud-devops-codescan@main with: parent_uid: ${{ secrets.ALI_PID }} private_key: ${{ secrets.ALI_PK }} From bff853f3665247fa24d3063d833d8ba2209ec4b4 Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 28 Aug 2023 16:41:33 +0800 Subject: [PATCH 03/64] fix directUrl transform exception (#1361) Co-authored-by: liujianjun.ljj --- .../java/com/alipay/sofa/rpc/registry/local/DomainRegistry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/registry-local/src/main/java/com/alipay/sofa/rpc/registry/local/DomainRegistry.java b/registry/registry-local/src/main/java/com/alipay/sofa/rpc/registry/local/DomainRegistry.java index d6cc90ae6..4b94f72b1 100644 --- a/registry/registry-local/src/main/java/com/alipay/sofa/rpc/registry/local/DomainRegistry.java +++ b/registry/registry-local/src/main/java/com/alipay/sofa/rpc/registry/local/DomainRegistry.java @@ -118,7 +118,7 @@ protected void refreshDomain() { } for (String directUrl : keySet) { - ProviderInfo providerInfo = ProviderHelper.toProviderInfo(directUrl); + ProviderInfo providerInfo = convertToProviderInfo(directUrl); List result = directUrl2IpUrl(providerInfo, domainCache.get(directUrl)); domainCache.put(directUrl, result); } From 7177205e4bd54fa0e45ad1e2101d0bdfd0b41ca6 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 28 Aug 2023 17:40:52 +0800 Subject: [PATCH 04/64] Sofaboot 4.0 support (#1356) * feat: let use of javassist compatible at jdk 17 * chore: use latest space id * feat: update dubbo to 3.1.4 * fix: zk version * version * update version * bump hessian * update version * add ci * set verison as 51100 * fix: destory * fix: unit test * remove aci on sofaboot-4.0-support * feat: update hessian to 3.5.0-SNAPSHOT * release version --------- Co-authored-by: junyuan Co-authored-by: Lo1nt --- all/pom.xml | 6 +- bom/pom.xml | 49 ++++++++++++--- bootstrap/bootstrap-dubbo/pom.xml | 2 +- .../dubbo/DubboConsumerBootstrap.java | 9 ++- .../rpc/bootstrap/dubbo/DubboConvertor.java | 13 ++-- .../dubbo/DubboProviderBootstrap.java | 4 +- .../rpc/bootstrap/dubbo/DubboSingleton.java | 10 +-- .../rpc/bootstrap/dubbo/DubooServerTest.java | 63 ++++++++++++++----- bootstrap/bootstrap-triple/pom.xml | 2 +- .../com/alipay/sofa/rpc/common/Version.java | 2 +- example/pom.xml | 9 ++- .../start/ZookeeperBoltClientMain.java | 7 ++- .../start/ZookeeperBoltServerMain.java | 11 +++- .../rpc/log/factory/RpcLoggerFactory.java | 2 +- pom.xml | 2 +- registry/registry-zk/pom.xml | 10 ++- test/test-integration-3rd/pom.xml | 2 +- .../rpc/bootstrap/dubbo/DubboServerTest.java | 32 ++++++++++ 18 files changed, 172 insertions(+), 63 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index bc7b13675..ba240f147 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.11.0-SNAPSHOT + 5.11.0 ${project.groupId}:${project.artifactId} @@ -57,9 +57,9 @@ utf-8 1.7.21 1.3.2 - 3.28.0-GA + 3.29.2-GA 4.1.44.Final - 3.4.0 + 3.5.0 3.6.3.Final 1.6.6 3.0.8 diff --git a/bom/pom.xml b/bom/pom.xml index 8d75765af..56f3a2de5 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,8 +10,8 @@ pom - 5.11.0-SNAPSHOT - 3.28.0-GA + 5.11.0 + 3.29.2-GA 1.9.8 4.1.77.Final @@ -20,9 +20,10 @@ 1.0.2.Final 3.4.10 7.5.4.v20111024 - 4.0.1 + 3.5.7 + 4.3.0 0.22.0 - 2.6.9 + 3.1.8 2.0.3 6.3.0 1.2.2 @@ -31,7 +32,7 @@ 32.0.0-jre 0.16.0 - 3.4.0 + 3.5.0 0.9.2 3.22.0 2.12.7 @@ -300,25 +301,41 @@ org.apache.curator - curator-recipes + curator-framework ${curator.version} + + + org.apache.zookeeper + zookeeper + + org.apache.curator - curator-test + curator-x-discovery ${curator.version} - test - zookeeper org.apache.zookeeper + zookeeper + + + + + org.apache.zookeeper + zookeeper + ${zookeeper.version} + + + io.netty + netty - com.alibaba + org.apache.dubbo dubbo ${dubbo.version} @@ -492,6 +509,18 @@ + + org.apache.curator + curator-test + ${curator.version} + + + org.apache.zookeeper + zookeeper + + + test + junit junit diff --git a/bootstrap/bootstrap-dubbo/pom.xml b/bootstrap/bootstrap-dubbo/pom.xml index 09d8f8865..12645457a 100644 --- a/bootstrap/bootstrap-dubbo/pom.xml +++ b/bootstrap/bootstrap-dubbo/pom.xml @@ -20,7 +20,7 @@ - com.alibaba + org.apache.dubbo dubbo diff --git a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConsumerBootstrap.java b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConsumerBootstrap.java index b86357544..1cc260735 100644 --- a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConsumerBootstrap.java +++ b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConsumerBootstrap.java @@ -16,7 +16,7 @@ */ package com.alipay.sofa.rpc.bootstrap.dubbo; -import com.alibaba.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.ReferenceConfig; import com.alipay.sofa.rpc.bootstrap.ConsumerBootstrap; import com.alipay.sofa.rpc.client.Cluster; import com.alipay.sofa.rpc.client.ProviderGroup; @@ -100,7 +100,7 @@ private void copyCommon(ConsumerConfig consumerConfig, ReferenceConfig ref private void copyApplication(ConsumerConfig consumerConfig, ReferenceConfig referenceConfig) { ApplicationConfig applicationConfig = consumerConfig.getApplication(); - com.alibaba.dubbo.config.ApplicationConfig dubboConfig = new com.alibaba.dubbo.config.ApplicationConfig(); + org.apache.dubbo.config.ApplicationConfig dubboConfig = new org.apache.dubbo.config.ApplicationConfig(); dubboConfig.setName(applicationConfig.getAppName()); referenceConfig.setApplication(dubboConfig); } @@ -140,11 +140,10 @@ private void copyConsumer(ConsumerConfig consumerConfig, ReferenceConfig r private void copyMethods(ConsumerConfig consumerConfig, ReferenceConfig referenceConfig) { Map methodConfigs = consumerConfig.getMethods(); if (CommonUtils.isNotEmpty(methodConfigs)) { - List dubboMethodConfigs = - new ArrayList(); + List dubboMethodConfigs = new ArrayList<>(); for (Map.Entry entry : methodConfigs.entrySet()) { MethodConfig methodConfig = entry.getValue(); - com.alibaba.dubbo.config.MethodConfig dubboMethodConfig = new com.alibaba.dubbo.config.MethodConfig(); + org.apache.dubbo.config.MethodConfig dubboMethodConfig = new org.apache.dubbo.config.MethodConfig(); dubboMethodConfig.setName(methodConfig.getName()); dubboMethodConfig.setParameters(methodConfig.getParameters()); dubboMethodConfig.setTimeout(methodConfig.getTimeout()); diff --git a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConvertor.java b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConvertor.java index a2f8958c6..4e627c8d9 100644 --- a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConvertor.java +++ b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboConvertor.java @@ -29,19 +29,18 @@ public class DubboConvertor { public static void copyRegistries(com.alipay.sofa.rpc.config.AbstractInterfaceConfig sofaConfig, - com.alibaba.dubbo.config.AbstractInterfaceConfig dubboConfig) { + org.apache.dubbo.config.AbstractInterfaceConfig dubboConfig) { List registryConfigs = sofaConfig.getRegistry(); if (CommonUtils.isNotEmpty(registryConfigs)) { - List dubboRegistryConfigs = - new ArrayList(); + List dubboRegistryConfigs = new ArrayList<>(); for (RegistryConfig registryConfig : registryConfigs) { // 生成并丢到缓存里 - com.alibaba.dubbo.config.RegistryConfig dubboRegistryConfig = DubboSingleton.REGISTRY_MAP + org.apache.dubbo.config.RegistryConfig dubboRegistryConfig = DubboSingleton.REGISTRY_MAP .get(registryConfig); if (dubboRegistryConfig == null) { - dubboRegistryConfig = new com.alibaba.dubbo.config.RegistryConfig(); + dubboRegistryConfig = new org.apache.dubbo.config.RegistryConfig(); copyRegistryFields(registryConfig, dubboRegistryConfig); - com.alibaba.dubbo.config.RegistryConfig old = DubboSingleton.REGISTRY_MAP.putIfAbsent( + org.apache.dubbo.config.RegistryConfig old = DubboSingleton.REGISTRY_MAP.putIfAbsent( registryConfig, dubboRegistryConfig); if (old != null) { dubboRegistryConfig = old; @@ -58,7 +57,7 @@ public static void copyRegistries(com.alipay.sofa.rpc.config.AbstractInterfaceCo } public static void copyRegistryFields(com.alipay.sofa.rpc.config.RegistryConfig sofaRegistryConfig, - com.alibaba.dubbo.config.RegistryConfig dubboRegistryConfig) { + org.apache.dubbo.config.RegistryConfig dubboRegistryConfig) { dubboRegistryConfig.setAddress(sofaRegistryConfig.getAddress()); dubboRegistryConfig.setProtocol(sofaRegistryConfig.getProtocol()); dubboRegistryConfig.setRegister(sofaRegistryConfig.isRegister()); diff --git a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboProviderBootstrap.java b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboProviderBootstrap.java index 0ce91a38a..324b8fff9 100644 --- a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboProviderBootstrap.java +++ b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboProviderBootstrap.java @@ -16,8 +16,8 @@ */ package com.alipay.sofa.rpc.bootstrap.dubbo; -import com.alibaba.dubbo.config.ProtocolConfig; -import com.alibaba.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ServiceConfig; import com.alipay.sofa.rpc.bootstrap.ProviderBootstrap; import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.common.Version; diff --git a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboSingleton.java b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboSingleton.java index 6e1153b44..b3e55b792 100644 --- a/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboSingleton.java +++ b/bootstrap/bootstrap-dubbo/src/main/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboSingleton.java @@ -16,12 +16,12 @@ */ package com.alipay.sofa.rpc.bootstrap.dubbo; -import com.alibaba.dubbo.config.DubboShutdownHook; -import com.alibaba.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProtocolConfig; import com.alipay.sofa.rpc.base.Destroyable; import com.alipay.sofa.rpc.config.RegistryConfig; import com.alipay.sofa.rpc.config.ServerConfig; import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import org.apache.dubbo.rpc.model.FrameworkModel; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -50,17 +50,17 @@ public void postDestroy() { /** * sofa.SeverConfig --> dubbo.ProtocolConfig */ - final static ConcurrentMap SERVER_MAP = new ConcurrentHashMap(); + final static ConcurrentMap SERVER_MAP = new ConcurrentHashMap<>(); /** * sofa.RegistryConfig --> dubbo.RegistryConfig */ - final static ConcurrentMap REGISTRY_MAP = new ConcurrentHashMap(); + final static ConcurrentMap REGISTRY_MAP = new ConcurrentHashMap<>(); /** * Destroy all dubbo resources */ public static void destroyAll() { - DubboShutdownHook.getDubboShutdownHook().destroyAll(); + FrameworkModel.defaultModel().destroy(); } } diff --git a/bootstrap/bootstrap-dubbo/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubooServerTest.java b/bootstrap/bootstrap-dubbo/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubooServerTest.java index 985d7b525..a702ff663 100644 --- a/bootstrap/bootstrap-dubbo/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubooServerTest.java +++ b/bootstrap/bootstrap-dubbo/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubooServerTest.java @@ -17,7 +17,7 @@ package com.alipay.sofa.rpc.bootstrap.dubbo; import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.constants.CommonConstants; import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.service.GenericService; import com.alipay.sofa.rpc.bootstrap.dubbo.demo.DemoService; @@ -32,6 +32,8 @@ import com.alipay.sofa.rpc.context.RpcInvokeContext; import com.alipay.sofa.rpc.context.RpcRunningState; import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import org.apache.dubbo.config.ConfigKeys; +import org.apache.dubbo.config.context.ConfigMode; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -52,10 +54,50 @@ public class DubooServerTest { ConsumerConfig consumerConfig; + private static String OLD_VALUE_SHUTDOWN_WAIT_KEY; + private static String OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE; + private static String OLD_VALUE_DUBBO_CONFIG_MODE; + //dubbo close wait time - @AfterClass + @BeforeClass public static void before() { - ConfigUtils.getProperties().put(Constants.SHUTDOWN_WAIT_KEY, "1"); + RpcRunningState.setUnitTestMode(true); + OLD_VALUE_SHUTDOWN_WAIT_KEY = System.getProperty(CommonConstants.SHUTDOWN_WAIT_KEY); + OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE = System + .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + OLD_VALUE_DUBBO_CONFIG_MODE = System.getProperty(ConfigKeys.DUBBO_CONFIG_MODE); + + System.setProperty(CommonConstants.SHUTDOWN_WAIT_KEY, "1"); + System.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, "true"); + System.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, ConfigMode.IGNORE.name()); + } + + @AfterClass + public static void after() { + if (OLD_VALUE_SHUTDOWN_WAIT_KEY == null) { + System.clearProperty(CommonConstants.SHUTDOWN_WAIT_KEY); + } else { + System.setProperty(CommonConstants.SHUTDOWN_WAIT_KEY, OLD_VALUE_SHUTDOWN_WAIT_KEY); + } + + if (OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE == null) { + System.clearProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + } else { + System.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, + OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + } + + if (OLD_VALUE_DUBBO_CONFIG_MODE == null) { + System.clearProperty(ConfigKeys.DUBBO_CONFIG_MODE); + } else { + System.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, OLD_VALUE_DUBBO_CONFIG_MODE); + } + } + + @After + public void afterMethod() { + RpcInternalContext.removeAllContext(); + RpcInvokeContext.removeContext(); } @Test @@ -288,7 +330,7 @@ public void testWithParameterWithVersion() { } } - @Test(expected = com.alibaba.dubbo.rpc.RpcException.class) + @Test(expected = org.apache.dubbo.rpc.RpcException.class) //同步调用,直连,dubbo 消费没有指定dubbo服务版本version public void testConsumerWithNoDubboServiceVersion() { // 只有1个线程 执行 @@ -324,17 +366,4 @@ public void testConsumerWithNoDubboServiceVersion() { Assert.assertTrue(result.equalsIgnoreCase("hello xxx")); } - - @BeforeClass - public static void adBeforeClass() { - RpcRunningState.setUnitTestMode(true); - } - - @After - public void afterMethod() { - DubboSingleton.destroyAll(); - RpcRuntimeContext.destroy(); - RpcInternalContext.removeAllContext(); - RpcInvokeContext.removeContext(); - } } \ No newline at end of file diff --git a/bootstrap/bootstrap-triple/pom.xml b/bootstrap/bootstrap-triple/pom.xml index 2d7e74c00..2eea9c3c2 100644 --- a/bootstrap/bootstrap-triple/pom.xml +++ b/bootstrap/bootstrap-triple/pom.xml @@ -19,7 +19,7 @@ - com.alibaba + org.apache.dubbo dubbo diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index f64663161..a9d42f390 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -37,6 +37,6 @@ public final class Version { /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.11.0_20230720235253"; + public static final String BUILD_VERSION = "5.11.0_20230828164355"; } diff --git a/example/pom.xml b/example/pom.xml index ca0b3cd87..4cf8c712c 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -108,14 +108,19 @@ - com.alibaba + org.apache.dubbo dubbo org.apache.curator - curator-recipes + curator-framework + test + + + org.apache.curator + curator-x-discovery test diff --git a/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltClientMain.java b/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltClientMain.java index 1568919c5..a4980a3dc 100644 --- a/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltClientMain.java +++ b/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltClientMain.java @@ -43,11 +43,14 @@ public static void main(String[] args) throws InterruptedException { /** * 运行需要pom.xml里增加依赖 - org.apache.curator - curator-recipes + curator-framework test + + org.apache.curator + curator-x-discovery + test */ RegistryConfig registryConfig = new RegistryConfig() .setProtocol(RpcConstants.REGISTRY_PROTOCOL_ZK) diff --git a/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltServerMain.java b/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltServerMain.java index 6eb1335ba..2950c2d29 100644 --- a/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltServerMain.java +++ b/example/src/test/java/com/alipay/sofa/rpc/zookeeper/start/ZookeeperBoltServerMain.java @@ -47,9 +47,14 @@ public static void main(String[] args) { /** * 运行需要pom.xml里增加依赖 - org.apache.curator - curator-recipes - test + org.apache.curator + curator-framework + test + + + org.apache.curator + curator-x-discovery + test */ RegistryConfig registryConfig = new RegistryConfig() diff --git a/log-common-tools/src/main/java/com/alipay/sofa/rpc/log/factory/RpcLoggerFactory.java b/log-common-tools/src/main/java/com/alipay/sofa/rpc/log/factory/RpcLoggerFactory.java index 22b656a58..521d8227d 100644 --- a/log-common-tools/src/main/java/com/alipay/sofa/rpc/log/factory/RpcLoggerFactory.java +++ b/log-common-tools/src/main/java/com/alipay/sofa/rpc/log/factory/RpcLoggerFactory.java @@ -17,7 +17,7 @@ package com.alipay.sofa.rpc.log.factory; import com.alipay.sofa.common.log.LoggerSpaceManager; -import com.alipay.sofa.common.log.SpaceId; +import com.alipay.sofa.common.space.SpaceId; import java.util.HashMap; import java.util.Map; diff --git a/pom.xml b/pom.xml index 4974403de..b4a630be9 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.11.0-SNAPSHOT + 5.11.0 1.33 true true diff --git a/registry/registry-zk/pom.xml b/registry/registry-zk/pom.xml index 093615afb..cd221fb02 100644 --- a/registry/registry-zk/pom.xml +++ b/registry/registry-zk/pom.xml @@ -28,7 +28,15 @@ org.apache.curator - curator-recipes + curator-framework + + + org.apache.curator + curator-x-discovery + + + org.apache.zookeeper + zookeeper diff --git a/test/test-integration-3rd/pom.xml b/test/test-integration-3rd/pom.xml index 81a723ccb..c64fcc0cd 100644 --- a/test/test-integration-3rd/pom.xml +++ b/test/test-integration-3rd/pom.xml @@ -38,7 +38,7 @@ - com.alibaba + org.apache.dubbo dubbo diff --git a/test/test-integration-3rd/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboServerTest.java b/test/test-integration-3rd/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboServerTest.java index b2820397b..98baa2684 100644 --- a/test/test-integration-3rd/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboServerTest.java +++ b/test/test-integration-3rd/src/test/java/com/alipay/sofa/rpc/bootstrap/dubbo/DubboServerTest.java @@ -28,7 +28,11 @@ import com.alipay.sofa.rpc.registry.base.BaseZkTest; import com.alipay.sofa.rpc.test.HelloService; import com.alipay.sofa.rpc.test.HelloServiceImpl; +import org.apache.dubbo.config.ConfigKeys; +import org.apache.dubbo.config.context.ConfigMode; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import java.util.ArrayList; @@ -39,6 +43,34 @@ */ public class DubboServerTest extends BaseZkTest { + private static String OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE; + private static String OLD_VALUE_DUBBO_CONFIG_MODE; + + @BeforeClass + public static void beforeClass() { + OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE = System + .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + OLD_VALUE_DUBBO_CONFIG_MODE = System.getProperty(ConfigKeys.DUBBO_CONFIG_MODE); + System.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, "true"); + System.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, ConfigMode.IGNORE.name()); + } + + @AfterClass + public static void afterClass() { + if (OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE != null) { + System.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, + OLD_VALUE_DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + } else { + System.clearProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + } + + if (OLD_VALUE_DUBBO_CONFIG_MODE != null) { + System.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, OLD_VALUE_DUBBO_CONFIG_MODE); + } else { + System.clearProperty(ConfigKeys.DUBBO_CONFIG_MODE); + } + } + @Test //同步调用,走服务注册中心 public void testRegistrySync() { From e3b64e607dafaa25a7574a2649b63ec5110defc6 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Mon, 11 Sep 2023 10:16:34 +0800 Subject: [PATCH 05/64] upgrade rpc version to 5.11.1-SNAPSHOT (#1366) Co-authored-by: Jason Song --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/resources/sofa-rpc/serialize_blacklist.txt | 1 + .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index ba240f147..645813288 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.11.0 + 5.11.1-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 56f3a2de5..503aa0d1e 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.11.0 + 5.11.1-SNAPSHOT 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt index 754494cd5..b25affe9a 100644 --- a/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt +++ b/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt @@ -25,6 +25,7 @@ javax.naming.spi.ObjectFactory javax.script.ScriptEngineManager javax.sound.sampled.AudioFormat$Encoding javax.sound.sampled.AudioFileFormat +javax.swing.UIDefaults org.apache.carbondata.core.scan.expression.ExpressionResult org.apache.commons.dbcp.datasources.SharedPoolDataSource org.apache.ibatis.executor.loader.AbstractSerialStateHolder diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index a9d42f390..6c9ba7b12 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.11.0"; + public static final String VERSION = "5.11.1"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51100; + public static final int RPC_VERSION = 51101; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.11.0_20230828164355"; + public static final String BUILD_VERSION = "5.11.1_20230911090800"; } diff --git a/pom.xml b/pom.xml index b4a630be9..49d8b9e99 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.11.0 + 5.11.1-SNAPSHOT 1.33 true true From 008d05a35d6e3d7403597dba420105a506ba2503 Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 11 Sep 2023 16:18:24 +0800 Subject: [PATCH 06/64] release 5.11.1 (#1367) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 645813288..e85bc1955 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.11.1-SNAPSHOT + 5.11.1 ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 503aa0d1e..5756a04f0 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.11.1-SNAPSHOT + 5.11.1 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 6c9ba7b12..7e51652d2 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -37,6 +37,6 @@ public final class Version { /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.11.1_20230911090800"; + public static final String BUILD_VERSION = "5.11.1_20230911155412"; } diff --git a/pom.xml b/pom.xml index 49d8b9e99..57e7f943e 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.11.1-SNAPSHOT + 5.11.1 1.33 true true From d9c2fac118b60c0a7e52652720bb936947159bf0 Mon Sep 17 00:00:00 2001 From: hacke2 Date: Tue, 26 Sep 2023 19:55:31 +0800 Subject: [PATCH 07/64] doc: add ant codespaces badge (#1370) --- README.md | 1 + README_zh_CN.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index d6f4a0914..fca3ecbba 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ![License](https://img.shields.io/badge/license-Apache--2.0-green.svg) [![Maven](https://img.shields.io/github/release/sofastack/sofa-rpc.svg)](https://github.com/sofastack/sofa-rpc/releases) [![Percentage of issues still open](https://isitmaintained.com/badge/open/sofastack/sofa-rpc.svg)](https://isitmaintained.com/project/sofastack/sofa-rpc "Percentage of issues still open") +[![Open in CodeBlitz](https://img.shields.io/badge/Ant_Codespaces-Open_in_CodeBlitz-1677ff)](https://codeblitz.cloud.alipay.com/github/sofastack/sofa-rpc) ## Overview diff --git a/README_zh_CN.md b/README_zh_CN.md index 6a9fbfcc1..c172a3c9b 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -4,6 +4,7 @@ [![Coverage Status](https://codecov.io/gh/sofastack/sofa-rpc/branch/master/graph/badge.svg)](https://codecov.io/gh/sofastack/sofa-rpc) ![License](https://img.shields.io/badge/license-Apache--2.0-green.svg) [![Maven](https://img.shields.io/github/release/sofastack/sofa-rpc.svg)](https://github.com/sofastack/sofa-rpc/releases) +[![Open in CodeBlitz](https://img.shields.io/badge/Ant_Codespaces-Open_in_CodeBlitz-1677ff)](https://codeblitz.cloud.alipay.com/github/sofastack/sofa-rpc) SOFARPC 是一个高可扩展性、高性能、生产级的 Java RPC 框架。在蚂蚁金服 SOFARPC 已经经历了十多年及五代版本的发展。SOFARPC 致力于简化应用之间的 RPC 调用,为应用提供方便透明、稳定高效的点对点远程服务调用方案。为了用户和开发者方便的进行功能扩展,SOFARPC 提供了丰富的模型抽象和可扩展接口,包括过滤器、路由、负载均衡等等。同时围绕 SOFARPC 框架及其周边组件提供丰富的微服务治理方案。 From 541c1600f2175754000bfe626e8c83a8851c549f Mon Sep 17 00:00:00 2001 From: Duan-0916 <76544421+Duan-0916@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:23:41 +0800 Subject: [PATCH 08/64] cloud_code_scan.yml (#1373) --- .github/workflows/cloud_code_scan.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cloud_code_scan.yml b/.github/workflows/cloud_code_scan.yml index c84cb387b..b46b90d56 100644 --- a/.github/workflows/cloud_code_scan.yml +++ b/.github/workflows/cloud_code_scan.yml @@ -1,11 +1,8 @@ name: Alipay Cloud Devops Codescan on: - push: - branches-ignore: - - 'dependabot/**' - + pull_request_target: jobs: - deployment: + stc: # 安全扫描 runs-on: ubuntu-latest steps: - name: codeScan @@ -13,3 +10,13 @@ jobs: with: parent_uid: ${{ secrets.ALI_PID }} private_key: ${{ secrets.ALI_PK }} + scan_type: stc + sca: # 开源合规 + runs-on: ubuntu-latest + steps: + - name: codeScan + uses: layotto/alipay-cloud-devops-codescan@main + with: + parent_uid: ${{ secrets.ALI_PID }} + private_key: ${{ secrets.ALI_PK }} + scan_type: sca From 1e99afbea021f39150c91fff2aa3efa11ed85881 Mon Sep 17 00:00:00 2001 From: Duan-0916 <76544421+Duan-0916@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:50:42 +0800 Subject: [PATCH 09/64] Update cloud_code_scan.yml (#1375) --- .github/workflows/cloud_code_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cloud_code_scan.yml b/.github/workflows/cloud_code_scan.yml index b46b90d56..f735fd3d9 100644 --- a/.github/workflows/cloud_code_scan.yml +++ b/.github/workflows/cloud_code_scan.yml @@ -2,7 +2,7 @@ name: Alipay Cloud Devops Codescan on: pull_request_target: jobs: - stc: # 安全扫描 + stc: #安全扫描 runs-on: ubuntu-latest steps: - name: codeScan From 7980b1f058a5b17532b7726390eb9b94f284d6f1 Mon Sep 17 00:00:00 2001 From: PAN <46820719+pandalee99@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:00:56 +0800 Subject: [PATCH 10/64] add fury serializer (#1348) * add FurySerializer --------- Co-authored-by: pankoli Co-authored-by: liujianjun.ljj Co-authored-by: Lo1nt --- all/pom.xml | 6 + bom/pom.xml | 6 + .../common/BlackAndWhiteListFileLoader.java} | 72 ++++- .../codec/common/SerializeCheckStatus.java | 48 +++ .../sofa-rpc/serialize_blacklist.txt | 0 codec/codec-sofa-fury/pom.xml | 46 +++ .../sofa/rpc/codec/fury/FurySerializer.java | 182 +++++++++++ .../serialize/SofaRequestFurySerializer.java | 117 +++++++ .../serialize/SofaResponseFurySerializer.java | 102 +++++++ .../com.alipay.sofa.rpc.codec.Serializer | 1 + .../rpc/codec/fury/FurySerializerTest.java | 289 ++++++++++++++++++ .../fury/model/blacklist/BlackListClass.java | 24 ++ .../model/none/NoneClassHasBlackClass.java | 36 +++ .../fury/model/whitelist/DemoRequest.java | 33 ++ .../fury/model/whitelist/DemoResponse.java | 50 +++ .../fury/model/whitelist/DemoService.java | 33 ++ .../whitelist/WhiteClassHasBlackClass.java | 35 +++ .../src/test/resources/log4j.xml | 16 + .../test/resources/sofa-rpc/rpc-config.json | 4 + .../sofa-rpc/serialize_blacklist.txt | 1 + .../sofa-rpc/serialize_whitelist.txt | 1 + .../sofahessian/SofaHessianSerializer.java | 3 +- ...a => BlackAndWhiteListFileLoaderTest.java} | 35 +-- codec/pom.xml | 1 + .../sofa/rpc/codec/AbstractSerializer.java | 17 ++ .../sofa/rpc/codec/CustomSerializer.java | 60 ++++ .../alipay/sofa/rpc/ext/ExtensionLoader.java | 3 +- .../alipay/sofa/rpc/common/SofaOptions.java | 4 + .../sofa/rpc/common/config/RpcConfigKeys.java | 28 ++ .../sofa/rpc/common/rpc-config-default.json | 2 +- 30 files changed, 1221 insertions(+), 34 deletions(-) rename codec/{codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java => codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java} (59%) create mode 100644 codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java rename codec/{codec-sofa-hessian => codec-api}/src/main/resources/sofa-rpc/serialize_blacklist.txt (100%) create mode 100644 codec/codec-sofa-fury/pom.xml create mode 100644 codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java create mode 100644 codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java create mode 100644 codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java create mode 100644 codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java create mode 100644 codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java create mode 100644 codec/codec-sofa-fury/src/test/resources/log4j.xml create mode 100644 codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json create mode 100644 codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt create mode 100644 codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt rename codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/{BlackListFileLoaderTest.java => BlackAndWhiteListFileLoaderTest.java} (71%) create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java diff --git a/all/pom.xml b/all/pom.xml index e85bc1955..8f92f16ce 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -183,6 +183,11 @@ sofa-rpc-codec-jackson ${project.version} + + com.alipay.sofa + sofa-rpc-codec-sofa-fury + ${project.version} + com.alipay.sofa sofa-rpc-fault-tolerance @@ -519,6 +524,7 @@ com.alipay.sofa:sofa-rpc-codec-jackson com.alipay.sofa:sofa-rpc-codec-msgpack com.alipay.sofa:sofa-rpc-codec-sofa-hessian + com.alipay.sofa:sofa-rpc-codec-sofa-fury com.alipay.sofa:sofa-rpc-fault-tolerance com.alipay.sofa:sofa-rpc-fault-hystrix com.alipay.sofa:sofa-rpc-log-common-tools diff --git a/bom/pom.xml b/bom/pom.xml index 5756a04f0..dabab0d2b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -39,6 +39,7 @@ 2.12.7.1 0.6.12 1.5.9 + 0.4.1 1.53.0 @@ -298,6 +299,11 @@ msgpack ${msgpack.version} + + org.furyio + fury-core + ${fury.version} + org.apache.curator diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java similarity index 59% rename from codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java rename to codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java index 8b48c7a7b..54f4ddf64 100644 --- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.rpc.codec.sofahessian; +package com.alipay.sofa.rpc.codec.common; -import com.alipay.sofa.rpc.common.SofaConfigs; -import com.alipay.sofa.rpc.common.SofaOptions; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.log.Logger; import com.alipay.sofa.rpc.log.LoggerFactory; @@ -30,6 +29,8 @@ import java.util.LinkedList; import java.util.List; +import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_BLACKLIST_OVERRIDE; +import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_WHITELIST_OVERRIDE; import static com.alipay.sofa.rpc.common.utils.IOUtils.closeQuietly; /** @@ -37,21 +38,24 @@ * * @author GengZhang */ -public class BlackListFileLoader { +public class BlackAndWhiteListFileLoader { - private static final Logger LOGGER = LoggerFactory.getLogger(BlackListFileLoader.class); + private static final Logger LOGGER = LoggerFactory + .getLogger(BlackAndWhiteListFileLoader.class); - public static final List SOFA_SERIALIZE_BLACK_LIST = loadFile("/sofa-rpc/serialize_blacklist.txt"); + public static final List SOFA_SERIALIZE_BLACK_LIST = loadBlackListFile("/sofa-rpc/serialize_blacklist.txt"); - static List loadFile(String path) { - List blackPrefixList = new ArrayList(); + public static final List SOFA_SERIALIZER_WHITE_LIST = loadWhiteListFile("/sofa-rpc/serialize_whitelist.txt"); + + public static List loadBlackListFile(String path) { + List blackPrefixList = new ArrayList<>(); InputStream input = null; try { - input = BlackListFileLoader.class.getResourceAsStream(path); + input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path); if (input != null) { readToList(input, "UTF-8", blackPrefixList); } - String overStr = SofaConfigs.getStringValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, ""); + String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_BLACKLIST_OVERRIDE, ""); if (StringUtils.isNotBlank(overStr)) { if (LOGGER.isInfoEnabled()) { LOGGER.info("Serialize blacklist will override with configuration: {}", overStr); @@ -68,6 +72,31 @@ static List loadFile(String path) { return blackPrefixList; } + public static List loadWhiteListFile(String path) { + List whitePrefixList = new ArrayList<>(); + InputStream input = null; + try { + input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path); + if (input != null) { + readToList(input, "UTF-8", whitePrefixList); + } + String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_WHITELIST_OVERRIDE, ""); + if (StringUtils.isNotBlank(overStr)) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Serialize whitelist will override with configuration: {}", overStr); + } + overrideWhiteList(whitePrefixList, overStr); + } + } catch (Exception e) { + if (LOGGER.isErrorEnabled()) { + LOGGER.error(e.getMessage(), e); + } + } finally { + closeQuietly(input); + } + return whitePrefixList; + } + /** * 读文件,将结果丢入List * @@ -100,12 +129,12 @@ private static void readToList(InputStream input, String encoding, List /** * Override blacklist with override string. - * - * @param originList Origin black list + * + * @param originList Origin black list * @param overrideStr The override string */ - static void overrideBlackList(List originList, String overrideStr) { - List adds = new LinkedList(); + public static void overrideBlackList(List originList, String overrideStr) { + List adds = new LinkedList<>(); String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr); for (String overrideItem : overrideItems) { if (StringUtils.isNotBlank(overrideItem)) { @@ -127,4 +156,19 @@ static void overrideBlackList(List originList, String overrideStr) { originList.addAll(adds); } } + + public static void overrideWhiteList(List originList, String overrideStr) { + List adds = new LinkedList<>(); + String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr); + for (String overrideItem : overrideItems) { + if (StringUtils.isNotBlank(overrideItem)) { + if (!originList.contains(overrideItem)) { + adds.add(overrideItem); + } + } + } + if (adds.size() > 0) { + originList.addAll(adds); + } + } } diff --git a/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java new file mode 100644 index 000000000..bcedf2101 --- /dev/null +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java @@ -0,0 +1,48 @@ +/* + * 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 com.alipay.sofa.rpc.codec.common; + +/** + * @author Even + * @date 2024/1/5 19:12 + */ +public enum SerializeCheckStatus { + /** + * Disable serialize check for all classes + */ + DISABLE(0), + + /** + * Only deny danger classes, warn if other classes are not in allow list + */ + WARN(1), + + /** + * Only allow classes in allow list, deny if other classes are not in allow list + */ + STRICT(2); + + private final int mode; + + SerializeCheckStatus(int mode) { + this.mode = mode; + } + + public int getSerializeCheckMode() { + return mode; + } +} diff --git a/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt similarity index 100% rename from codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt rename to codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt diff --git a/codec/codec-sofa-fury/pom.xml b/codec/codec-sofa-fury/pom.xml new file mode 100644 index 000000000..70150a8f9 --- /dev/null +++ b/codec/codec-sofa-fury/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + + com.alipay.sofa + sofa-rpc-codec + ${revision} + + + sofa-rpc-codec-sofa-fury + + + + com.alipay.sofa + sofa-rpc-codec-api + + + com.alipay.sofa + sofa-rpc-api + + + com.alipay.sofa + sofa-rpc-log + + + + + org.furyio + fury-core + + + + org.slf4j + slf4j-log4j12 + test + + + junit + junit + test + + + diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java new file mode 100644 index 000000000..e1a61a6fd --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java @@ -0,0 +1,182 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury; + +import com.alipay.sofa.common.config.SofaConfigs; +import com.alipay.sofa.rpc.codec.AbstractSerializer; +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; +import com.alipay.sofa.rpc.codec.common.SerializeCheckStatus; +import com.alipay.sofa.rpc.codec.fury.serialize.SofaRequestFurySerializer; +import com.alipay.sofa.rpc.codec.fury.serialize.SofaResponseFurySerializer; +import com.alipay.sofa.rpc.common.config.RpcConfigKeys; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.Fury; +import io.fury.ThreadLocalFury; +import io.fury.config.Language; +import io.fury.memory.MemoryBuffer; +import io.fury.resolver.AllowListChecker; + +import java.util.List; +import java.util.Map; + +import static io.fury.config.CompatibleMode.COMPATIBLE; + +/** + * @author lipan + */ +@Extension(value = "fury2", code = 22) +public class FurySerializer extends AbstractSerializer { + + private final ThreadLocalFury fury; + + private final String checkerMode = SofaConfigs.getOrDefault(RpcConfigKeys.SERIALIZE_CHECKER_MODE); + + public FurySerializer() { + fury = new ThreadLocalFury(classLoader -> { + Fury f = Fury.builder().withLanguage(Language.JAVA) + .withRefTracking(true) + .withCodegen(true) + .withNumberCompressed(true) + .withCompatibleMode(COMPATIBLE) + .requireClassRegistration(false) + .withClassLoader(classLoader) + .withAsyncCompilation(true) + .build(); + + // Do not use any configuration + if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.DISABLE.name())) { + AllowListChecker noChecker = new AllowListChecker(AllowListChecker.CheckLevel.DISABLE); + f.getClassResolver().setClassChecker(noChecker); + return f; + } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.WARN.name())) { + AllowListChecker blackListChecker = new AllowListChecker(AllowListChecker.CheckLevel.WARN); + List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackListChecker); + blackListChecker.addListener(f.getClassResolver()); + // BlackList classes use wildcards + for (String key : blackList) { + blackListChecker.disallowClass(key + "*"); + } + } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.STRICT.name())) { + AllowListChecker blackAndWhiteListChecker = new AllowListChecker(AllowListChecker.CheckLevel.STRICT); + List whiteList = BlackAndWhiteListFileLoader.SOFA_SERIALIZER_WHITE_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackAndWhiteListChecker); + blackAndWhiteListChecker.addListener(f.getClassResolver()); + // WhiteList classes use wildcards + for (String key : whiteList) { + blackAndWhiteListChecker.allowClass(key + "*"); + } + List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + // To setting checker + f.getClassResolver().setClassChecker(blackAndWhiteListChecker); + blackAndWhiteListChecker.addListener(f.getClassResolver()); + // BlackList classes use wildcards + for (String key : blackList) { + blackAndWhiteListChecker.disallowClass(key + "*"); + } + } + f.register(SofaRequest.class); + f.register(SofaResponse.class); + f.register(SofaRpcException.class); + return f; + }); + addSerializer(SofaRequest.class, new SofaRequestFurySerializer(fury)); + addSerializer(SofaResponse.class, new SofaResponseFurySerializer(fury)); + } + + @Override + public AbstractByteBuf encode(final Object object, final Map context) throws SofaRpcException { + if (object == null) { + throw buildSerializeError("Unsupported null message!"); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getObjCustomSerializer(object); + if (customSerializer != null) { + return customSerializer.encodeObject(object, context); + } else { + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + fury.serialize(writeBuffer, object); + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } + } catch (Exception e) { + throw buildSerializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + @Override + public Object decode(final AbstractByteBuf data, final Class clazz, final Map context) + throws SofaRpcException { + if (data.readableBytes() <= 0 || clazz == null) { + throw buildDeserializeError("Deserialized array is empty."); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getSerializer(clazz); + if (customSerializer != null) { + return customSerializer.decodeObject(data, context); + } else { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + return fury.deserialize(readBuffer); + } + } catch (Exception e) { + throw buildDeserializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + @Override + public void decode(final AbstractByteBuf data, final Object template, final Map context) + throws SofaRpcException { + if (template == null) { + throw buildDeserializeError("template is null!"); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + fury.setClassLoader(contextClassLoader); + CustomSerializer customSerializer = getObjCustomSerializer(template); + if (customSerializer != null) { + customSerializer.decodeObjectByTemplate(data, context, template); + } else { + throw buildDeserializeError("Only support decode from SofaRequest and SofaResponse template"); + } + } catch (Exception e) { + throw buildDeserializeError(e.getMessage(), e); + } finally { + fury.clearClassLoader(contextClassLoader); + } + } + + public ThreadLocalFury getFury() { + return fury; + } + +} diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java new file mode 100644 index 000000000..9122c0c18 --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java @@ -0,0 +1,117 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.serialize; + +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.ThreadLocalFury; +import io.fury.memory.MemoryBuffer; + +import java.util.Map; + +/** + * @author Even + * @date 2024/1/4 19:29 + */ +public class SofaRequestFurySerializer implements CustomSerializer { + + private final ThreadLocalFury fury; + + public SofaRequestFurySerializer(ThreadLocalFury fury) { + this.fury = fury; + } + + @Override + public AbstractByteBuf encodeObject(SofaRequest object, Map context) throws SofaRpcException { + try { + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + + // 根据SerializeType信息决定序列化器 + boolean genericSerialize = context != null && + isGenericRequest(context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } + fury.serialize(writeBuffer, object); + final Object[] args = object.getMethodArgs(); + fury.serialize(writeBuffer, args); + + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public SofaRequest decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + try { + SofaRequest sofaRequest = (SofaRequest) fury.deserialize(readBuffer); + String targetServiceName = sofaRequest.getTargetServiceUniqueName(); + if (targetServiceName == null) { + throw new SofaRpcException("Target service name of request is null!"); + } + String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName); + sofaRequest.setInterfaceName(interfaceName); + final Object[] args = (Object[]) fury.deserialize(readBuffer); + sofaRequest.setMethodArgs(args); + return sofaRequest; + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaRequest template) + throws SofaRpcException { + if (data.readableBytes() <= 0) { + throw new SofaRpcException("Deserialized array is empty."); + } + try { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + SofaRequest tmp = (SofaRequest) fury.deserialize(readBuffer); + String targetServiceName = tmp.getTargetServiceUniqueName(); + if (targetServiceName == null) { + throw new SofaRpcException("Target service name of request is null!"); + } + // copy values to template + template.setMethodName(tmp.getMethodName()); + template.setMethodArgSigs(tmp.getMethodArgSigs()); + template.setTargetServiceUniqueName(tmp.getTargetServiceUniqueName()); + template.setTargetAppName(tmp.getTargetAppName()); + template.addRequestProps(tmp.getRequestProps()); + String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName); + template.setInterfaceName(interfaceName); + final Object[] args = (Object[]) fury.deserialize(readBuffer); + template.setMethodArgs(args); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + protected boolean isGenericRequest(String serializeType) { + return serializeType != null && !serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_NORMAL); + } + +} diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java new file mode 100644 index 000000000..9a7402ab1 --- /dev/null +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java @@ -0,0 +1,102 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.serialize; + +import com.alipay.sofa.rpc.codec.CustomSerializer; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import io.fury.ThreadLocalFury; +import io.fury.memory.MemoryBuffer; + +import java.util.Map; + +/** + * @author Even + * @date 2024/1/4 19:30 + */ +public class SofaResponseFurySerializer implements CustomSerializer { + + private final ThreadLocalFury fury; + + public SofaResponseFurySerializer(ThreadLocalFury fury) { + this.fury = fury; + } + + @Override + public AbstractByteBuf encodeObject(SofaResponse object, Map context) throws SofaRpcException { + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); + writeBuffer.writerIndex(0); + fury.serialize(writeBuffer, object); + return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public SofaResponse decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException { + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + boolean genericSerialize = context != null && isGenericResponse( + context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } + return (SofaResponse) fury.deserialize(readBuffer); + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + @Override + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaResponse template) + throws SofaRpcException { + if (data.readableBytes() <= 0) { + throw new SofaRpcException("Deserialized array is empty."); + } + try { + fury.setClassLoader(Thread.currentThread().getContextClassLoader()); + MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); + // 根据SerializeType信息决定序列化器 + boolean genericSerialize = context != null && isGenericResponse( + context.get(RemotingConstants.HEAD_GENERIC_TYPE)); + if (genericSerialize) { + // TODO support generic call + throw new SofaRpcException("Generic call is not supported for now."); + } else { + SofaResponse tmp = (SofaResponse) fury.deserialize(readBuffer); + // copy values to template + template.setErrorMsg(tmp.getErrorMsg()); + template.setAppResponse(tmp.getAppResponse()); + template.setResponseProps(tmp.getResponseProps()); + } + } catch (Exception e) { + throw new SofaRpcException(e.getMessage(), e); + } + } + + protected boolean isGenericResponse(String serializeType) { + return serializeType != null && serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_GENERIC); + } +} diff --git a/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer new file mode 100644 index 000000000..dc727a0dd --- /dev/null +++ b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer @@ -0,0 +1 @@ +fury2=com.alipay.sofa.rpc.codec.fury.FurySerializer \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java new file mode 100644 index 000000000..fc4fde8cc --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java @@ -0,0 +1,289 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury; + +import com.alipay.sofa.rpc.codec.Serializer; +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; +import com.alipay.sofa.rpc.codec.fury.model.none.NoneClassHasBlackClass; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoRequest; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoResponse; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.WhiteClassHasBlackClass; +import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoService; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback; +import com.alipay.sofa.rpc.core.request.RequestBase; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author lipan + */ +public class FurySerializerTest { + + private final FurySerializer serializer = (FurySerializer) ExtensionLoaderFactory.getExtensionLoader( + Serializer.class).getExtension("fury2"); + + @Test + public void encodeAndDecode() { + try { + serializer.encode(null, null); + Assert.fail(); + } catch (Exception e) { + + } + + DemoRequest demoRequest = new DemoRequest(); + demoRequest.setName("a"); + AbstractByteBuf byteBuf = serializer.encode(demoRequest, null); + DemoRequest req2 = (DemoRequest) serializer.decode(byteBuf, DemoRequest.class, null); + Assert.assertEquals(demoRequest.getName(), req2.getName()); + + AbstractByteBuf data = serializer.encode("xxx", null); + String dst = (String) serializer.decode(data, String.class, null); + Assert.assertEquals("xxx", dst); + + try { + serializer.decode(data, null, null); + Assert.fail(); + } catch (Exception e) { + } + + try { + serializer.decode(data, "", null); + Assert.fail(); + } catch (Exception e) { + + } + } + + @Test + public void testSofaRequest() throws Exception { + SofaRequest request = buildRequest(); + AbstractByteBuf data = serializer.encode(request, null); + + serializer.encode("123456", null); + SofaRequest decode = (SofaRequest) serializer.decode(data, SofaRequest.class, null); + assertEqualsSofaRequest(request, decode); + + SofaRequest newRequest = new SofaRequest(); + serializer.decode(data, newRequest, null); + assertEqualsSofaRequest(request, newRequest); + + // null request + newRequest = new SofaRequest(); + try { + serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newRequest, null); + Assert.fail(); + } catch (Exception e) { + + } + } + + @Test + public void testSofaResponse() throws Exception { + SofaResponse response = new SofaResponse(); + final DemoResponse demoAppResponse = new DemoResponse(); + demoAppResponse.setWord("result"); + response.setAppResponse(demoAppResponse); + AbstractByteBuf data = serializer.encode(response, null); + + try { + serializer.decode(data, null, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.decode(data, new Object(), null); + Assert.fail(); + } catch (Exception e) { + + } + + SofaResponse decode = (SofaResponse) serializer.decode(data, SofaResponse.class, null); + Assert.assertFalse(decode.isError()); + Assert.assertEquals(response.getAppResponse(), decode.getAppResponse()); + Assert.assertEquals("result", ((DemoResponse) decode.getAppResponse()).getWord()); + + // success response + SofaResponse newResponse = new SofaResponse(); + serializer.decode(data, newResponse, null); + Assert.assertFalse(newResponse.isError()); + Assert.assertEquals(response.getAppResponse(), newResponse.getAppResponse()); + Assert.assertEquals("result", ((DemoResponse) newResponse.getAppResponse()).getWord()); + + // null response + newResponse = new SofaResponse(); + try { + serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newResponse, null); + Assert.fail(); + } catch (Exception e) { + + } + // error response + response = new SofaResponse(); + response.setErrorMsg("1233"); + data = serializer.encode(response, null); + newResponse = new SofaResponse(); + serializer.decode(data, newResponse, null); + Assert.assertTrue(newResponse.isError()); + Assert.assertEquals(response.getErrorMsg(), newResponse.getErrorMsg()); + } + + private SofaRequest buildRequest() throws NoSuchMethodException { + SofaRequest request = new SofaRequest(); + request.setInterfaceName(DemoService.class.getName()); + request.setMethodName("say"); + request.setMethod(DemoService.class.getMethod("say", DemoRequest.class)); + final DemoRequest demoRequest = new DemoRequest(); + demoRequest.setName("name"); + request.setMethodArgs(new Object[] { demoRequest }); + request.setMethodArgSigs(new String[] { DemoRequest.class.getCanonicalName() }); + request.setTargetServiceUniqueName(DemoService.class.getName() + ":1.0"); + request.setTargetAppName("targetApp"); + request.setSerializeType((byte) 22); + request.setTimeout(1024); + request.setInvokeType(RpcConstants.INVOKER_TYPE_SYNC); + Map map = new HashMap(); + map.put("a", "xxx"); + map.put("b", "yyy"); + request.addRequestProp(RemotingConstants.RPC_TRACE_NAME, map); + request.setSofaResponseCallback(new SofaResponseCallback() { + @Override + public void onAppResponse(Object appResponse, String methodName, RequestBase request) { + + } + + @Override + public void onAppException(Throwable throwable, String methodName, RequestBase request) { + + } + + @Override + public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) { + + } + }); + return request; + } + + private void assertEqualsSofaRequest(SofaRequest request, SofaRequest decode) { + Assert.assertEquals(decode.getInterfaceName(), request.getInterfaceName()); + Assert.assertEquals(decode.getMethodName(), request.getMethodName()); + Assert.assertArrayEquals(decode.getMethodArgSigs(), request.getMethodArgSigs()); + Assert.assertEquals(decode.getMethodArgs().length, request.getMethodArgs().length); + Assert.assertEquals("name", ((DemoRequest) decode.getMethodArgs()[0]).getName()); + Assert.assertEquals(decode.getTargetServiceUniqueName(), request.getTargetServiceUniqueName()); + Assert.assertEquals(decode.getTargetAppName(), request.getTargetAppName()); + Assert.assertEquals(decode.getRequestProp(RemotingConstants.RPC_TRACE_NAME), + request.getRequestProp(RemotingConstants.RPC_TRACE_NAME)); + } + + @Test + public void testChecker() throws Exception { + // default fury checkMode is STRICT + WhiteClassHasBlackClass whiteClassNullBlackClass = new WhiteClassHasBlackClass(); + NoneClassHasBlackClass noneClassNullBlackClass = new NoneClassHasBlackClass(); + + BlackListClass blackListClass = new BlackListClass(); + WhiteClassHasBlackClass whiteClassHasBlackClass = new WhiteClassHasBlackClass(); + whiteClassHasBlackClass.setBlackListClass(blackListClass); + NoneClassHasBlackClass noneClassHasBlackClass = new NoneClassHasBlackClass(); + noneClassHasBlackClass.setBlackListClass(blackListClass); + + try { + serializer.encode(noneClassNullBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.encode(noneClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + serializer.encode(blackListClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + serializer.encode(whiteClassNullBlackClass, null); + try { + serializer.encode(whiteClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + // test change fury checkMode to blacklist + System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "WARN"); + FurySerializer furySerializer = new FurySerializer(); + + furySerializer.encode(noneClassNullBlackClass, null); + + try { + furySerializer.encode(noneClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + try { + //Not registered this class + furySerializer.encode(blackListClass, null); + Assert.fail(); + } catch (Exception e) { + + } + + furySerializer.encode(whiteClassNullBlackClass, null); + try { + furySerializer.encode(whiteClassHasBlackClass, null); + Assert.fail(); + } catch (Exception e) { + + } + System.getProperties().remove("sofa.rpc.codec.serialize.checkMode"); + + // test change fury checkMode to none + System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "DISABLE"); + FurySerializer noneFurySerializer = new FurySerializer(); + noneFurySerializer.encode(noneClassNullBlackClass, null); + noneFurySerializer.encode(noneClassHasBlackClass, null); + noneFurySerializer.encode(blackListClass, null); + noneFurySerializer.encode(whiteClassNullBlackClass, null); + noneFurySerializer.encode(whiteClassHasBlackClass, null); + System.getProperties().remove("sofa.rpc.codec.serialize.checkMode"); + } + +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java new file mode 100644 index 000000000..78281a910 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java @@ -0,0 +1,24 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.model.blacklist; + +/** + * @author lipan + */ +public class BlackListClass { + private String test; +} diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java new file mode 100644 index 000000000..8ddaaa9a8 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java @@ -0,0 +1,36 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.model.none; + +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; + +/** + * @author Even + * @date 2024/1/2 11:33 + */ +public class NoneClassHasBlackClass { + + private BlackListClass blackListClass; + + public BlackListClass getBlackListClass() { + return blackListClass; + } + + public void setBlackListClass(BlackListClass blackListClass) { + this.blackListClass = blackListClass; + } +} diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java new file mode 100644 index 000000000..7b9bb7129 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java @@ -0,0 +1,33 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist; + +/** + * @author lipan + */ +public class DemoRequest { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java new file mode 100644 index 000000000..ffca06616 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java @@ -0,0 +1,50 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist; + +/** + * @author lipan + */ +public class DemoResponse { + + private String word; + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof DemoResponse)) + return false; + + DemoResponse that = (DemoResponse) o; + + return word != null ? word.equals(that.word) : that.word == null; + } + + @Override + public int hashCode() { + return word != null ? word.hashCode() : 0; + } +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java new file mode 100644 index 000000000..604473b7b --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java @@ -0,0 +1,33 @@ +/* + * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist; + +import java.util.List; +import java.util.Map; + +/** + * @author lipan + */ +public interface DemoService { + + public DemoResponse say(DemoRequest demoRequest); + + public DemoResponse say2(DemoRequest demoRequest, Map ctx, int id); + + public List say3(List list); + +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java new file mode 100644 index 000000000..10e3943fb --- /dev/null +++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.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 com.alipay.sofa.rpc.codec.fury.model.whitelist; + +import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass; + +/** + * @author lipan + */ +public class WhiteClassHasBlackClass { + + private BlackListClass blackListClass; + + public BlackListClass getBlackListClass() { + return blackListClass; + } + + public void setBlackListClass(BlackListClass blackListClass) { + this.blackListClass = blackListClass; + } +} diff --git a/codec/codec-sofa-fury/src/test/resources/log4j.xml b/codec/codec-sofa-fury/src/test/resources/log4j.xml new file mode 100644 index 000000000..e95634f16 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json new file mode 100644 index 000000000..5b573549a --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json @@ -0,0 +1,4 @@ +{ + "rpc.config.order": 999, + "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl" +} \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt new file mode 100644 index 000000000..991e2a54d --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt @@ -0,0 +1 @@ +com.alipay.sofa.rpc.codec.fury.model.blacklist. \ No newline at end of file diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt new file mode 100644 index 000000000..6f1718654 --- /dev/null +++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt @@ -0,0 +1 @@ +com.alipay.sofa.rpc.codec.fury.model.whitelist. \ No newline at end of file diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java index ae7eac3f0..06ec4a4a6 100644 --- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java +++ b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java @@ -19,6 +19,7 @@ import com.alipay.hessian.ClassNameResolver; import com.alipay.hessian.NameBlackListFilter; import com.alipay.sofa.rpc.codec.AbstractSerializer; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; import com.alipay.sofa.rpc.codec.sofahessian.serialize.CustomHessianSerializer; import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaRequestHessianSerializer; import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaResponseHessianSerializer; @@ -95,7 +96,7 @@ public SofaHessianSerializer() { if (RpcConfigs.getBooleanValue(RpcOptions.SERIALIZE_BLACKLIST_ENABLE) && SofaConfigs.getBooleanValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST, true)) { ClassNameResolver resolver = new ClassNameResolver(); - resolver.addFilter(new NameBlackListFilter(BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192)); + resolver.addFilter(new NameBlackListFilter(BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192)); serializerFactory.setClassNameResolver(resolver); genericSerializerFactory.setClassNameResolver(resolver); } else { diff --git a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java similarity index 71% rename from codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java rename to codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java index df934b6a1..05d279e4f 100644 --- a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java +++ b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java @@ -17,6 +17,7 @@ package com.alipay.sofa.rpc.codec.sofahessian; import com.alipay.hessian.NameBlackListFilter; +import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader; import com.alipay.sofa.rpc.common.SofaOptions; import org.junit.Assert; import org.junit.Test; @@ -29,17 +30,17 @@ * * @author GengZhang */ -public class BlackListFileLoaderTest { +public class BlackAndWhiteListFileLoaderTest { @Test public void testAll() throws Exception { - List blacks = BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST; + List blacks = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST; Assert.assertNotNull(blacks); String s = System.getProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE); try { System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, "-java.net.Socket"); - blacks = BlackListFileLoader.loadFile("/sofa-rpc/serialize_blacklist.txt"); + blacks = BlackAndWhiteListFileLoader.loadBlackListFile("/sofa-rpc/serialize_blacklist.txt"); } finally { if (s != null) { System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, s); @@ -69,51 +70,51 @@ public void testAll() throws Exception { @Test public void overrideBlackList() { List origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "!*"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "!*"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-default"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-default"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "!default"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "!default"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*,-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,-com.xxx"); Assert.assertTrue(origin.size() == 0); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-*,aaa"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,aaa"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-com.xxx"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx"); Assert.assertTrue(origin.size() == 2); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy"); Assert.assertTrue(origin.size() == 1); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy"); Assert.assertTrue(origin.size() == 2); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy"); Assert.assertTrue(origin.size() == 3); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa"); Assert.assertTrue(origin.size() == 4); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz"); Assert.assertTrue(origin.size() == 3); origin = buildOriginList(); - BlackListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc"); + BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc"); Assert.assertTrue(origin.size() == 6); } diff --git a/codec/pom.xml b/codec/pom.xml index 2ca5db8c2..25814b811 100644 --- a/codec/pom.xml +++ b/codec/pom.xml @@ -20,6 +20,7 @@ codec-protostuff codec-sofa-hessian codec-msgpack + codec-sofa-fury diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java index 0b9ebc0eb..efe20c953 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java @@ -33,6 +33,8 @@ public abstract class AbstractSerializer implements Serializer { protected static Map genericServiceMap = new ConcurrentHashMap<>(); + protected Map customSerializers = new ConcurrentHashMap<>(); + protected SofaRpcException buildSerializeError(String message) { return new SofaRpcException(getErrorCode(true), LogCodes.getLog(LogCodes.ERROR_SERIALIZER, message)); } @@ -73,4 +75,19 @@ public static void registerGenericService(String serviceName, String className) public static void clear() { genericServiceMap.clear(); } + + protected CustomSerializer getObjCustomSerializer(Object obj) { + if (obj == null) { + return null; + } + return getSerializer(obj.getClass()); + } + + protected CustomSerializer getSerializer(Class clazz) { + return customSerializers.get(clazz); + } + + protected void addSerializer(Class clazz, CustomSerializer serializerManager) { + customSerializers.put(clazz, serializerManager); + } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java new file mode 100644 index 000000000..42a4f6398 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java @@ -0,0 +1,60 @@ +/* + * 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 com.alipay.sofa.rpc.codec; + +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.transport.AbstractByteBuf; + +import java.util.Map; + +/** + * @author leizhiyuan + */ +public interface CustomSerializer { + + /** + * 序列化 + * + * @param object 对象 + * @param context 上下文 + * @return 序列化后的对象 + * @throws SofaRpcException 序列化异常 + */ + public AbstractByteBuf encodeObject(T object, Map context) throws SofaRpcException; + + /** + * 反序列化,只有类型,返回对象 + * + * @param data 原始字节数组 + * @param context 上下文 + * @return 反序列化后的对象 + * @throws SofaRpcException 序列化异常 + */ + public T decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException; + + /** + * 反序列化,已有数据,填充字段 + * + * @param data 原始字节数组 + * @param template 模板对象 + * @param context 上下文 + * @throws SofaRpcException 序列化异常 + */ + public void decodeObjectByTemplate(AbstractByteBuf data, Map context, T template) + throws SofaRpcException; + +} \ No newline at end of file diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java index 8deb9200f..0e36f2365 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java @@ -34,6 +34,7 @@ import java.io.InputStreamReader; import java.lang.reflect.Modifier; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -184,7 +185,7 @@ protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName) } BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8")); + reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { readLine(url, line); diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java index ae46681d5..4a9e1753c 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java @@ -160,6 +160,10 @@ public class SofaOptions { * 序列化覆盖 */ public static final String CONFIG_SERIALIZE_BLACKLIST_OVERRIDE = "rpc_serialize_blacklist_override"; + /** + * 序列化覆盖 + */ + public static final String CONFIG_SERIALIZE_WHITELIST_OVERRIDE = "rpc_serialize_whitelist_override"; //========= GRPC 相关配置 ========== /** diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java index 11fc481c5..bba581abf 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java @@ -18,6 +18,9 @@ import com.alipay.sofa.common.config.ConfigKey; +import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE; +import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_WHITELIST_OVERRIDE; + /** * @author zhaowang * @version : RpcConfigKeys.java, v 0.1 2020年12月14日 9:56 下午 zhaowang Exp $ @@ -102,4 +105,29 @@ public class RpcConfigKeys { false, "judge the generic object exception fields.", new String[] { "sofa_rpc_generic_exception_fields" }); + + public static final ConfigKey SERIALIZE_BLACKLIST_OVERRIDE = ConfigKey + .build( + "sofa.rpc.serialize.blacklist.override", + "", + false, + "Additional serialization blacklist.", + new String[] { CONFIG_SERIALIZE_BLACKLIST_OVERRIDE }); + + public static final ConfigKey SERIALIZE_WHITELIST_OVERRIDE = ConfigKey + .build( + "sofa.rpc.serialize.whitelist.override", + "", + false, + "Additional serialization whitelist.", + new String[] { CONFIG_SERIALIZE_WHITELIST_OVERRIDE }); + + public static final ConfigKey SERIALIZE_CHECKER_MODE = ConfigKey + .build( + "sofa.rpc.codec.serialize.checkMode", + "STRICT", + true, + " The default filtering mode is STRICT.You can also set WARN or DISABLE", + new String[] { "sofa_rpc_codec_serialize_checkMode" }); + } diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json index 9becfcf3f..6ad8f836f 100644 --- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json +++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json @@ -17,7 +17,7 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支 "META-INF/services/" ], // 需要被加载的模块列表,多个用逗号隔开 - "module.load.list" : "*", + "module.load.list": "*", /*-------------RPC框架内部使用配置项-------------*/ From f4b4ed5bb7d55ad98cba6ec0855a494a8b094c28 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 8 Jan 2024 15:42:12 +0800 Subject: [PATCH 11/64] bump hessian to 3.5.2 (#1385) Co-authored-by: Lo1nt --- all/pom.xml | 2 +- bom/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 8f92f16ce..8a88e5d43 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -59,7 +59,7 @@ 1.3.2 3.29.2-GA 4.1.44.Final - 3.5.0 + 3.5.2 3.6.3.Final 1.6.6 3.0.8 diff --git a/bom/pom.xml b/bom/pom.xml index dabab0d2b..9a132358b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -32,7 +32,7 @@ 32.0.0-jre 0.16.0 - 3.5.0 + 3.5.2 0.9.2 3.22.0 2.12.7 From d08e25824ae9feaf0876adba9acd2938f34759b1 Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 8 Jan 2024 17:44:34 +0800 Subject: [PATCH 12/64] Merge pull request from GHSA-7q8p-9953-pxvr Co-authored-by: liujianjun.ljj --- .../sofa-rpc/serialize_blacklist.txt | 228 +++++++++++++----- 1 file changed, 174 insertions(+), 54 deletions(-) diff --git a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt index b25affe9a..58269f895 100644 --- a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt +++ b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt @@ -1,54 +1,174 @@ -clojure.core$constantly -clojure.main$eval_opt -com.alibaba.citrus.springext.support.parser.AbstractNamedProxyBeanDefinitionParser$ProxyTargetFactory -com.alibaba.citrus.springext.support.parser.AbstractNamedProxyBeanDefinitionParser$ProxyTargetFactoryImpl -com.alibaba.citrus.springext.util.SpringExtUtil.AbstractProxy -com.alipay.custrelation.service.model.redress.Pair -com.caucho.hessian.test.TestCons -com.mchange.v2.c3p0.JndiRefForwardingDataSource -com.mchange.v2.c3p0.WrapperConnectionPoolDataSource -com.rometools.rome.feed.impl.EqualsBean -com.rometools.rome.feed.impl.ToStringBean -com.sun.jndi.rmi.registry.BindingEnumeration -com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl -com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl -com.sun.rowset.JdbcRowSetImpl -com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data -java.rmi.server.UnicastRemoteObject -java.security.SignedObject -java.util.ServiceLoader$LazyIterator -javax.imageio.ImageIO$ContainsFilter -javax.imageio.spi.ServiceRegistry -javax.management.BadAttributeValueExpException -javax.naming.InitialContext -javax.naming.spi.ObjectFactory -javax.script.ScriptEngineManager -javax.sound.sampled.AudioFormat$Encoding -javax.sound.sampled.AudioFileFormat -javax.swing.UIDefaults -org.apache.carbondata.core.scan.expression.ExpressionResult -org.apache.commons.dbcp.datasources.SharedPoolDataSource -org.apache.ibatis.executor.loader.AbstractSerialStateHolder -org.apache.ibatis.executor.loader.CglibSerialStateHolder -org.apache.ibatis.executor.loader.JavassistSerialStateHolder -org.apache.ibatis.executor.loader.cglib.CglibProxyFactory -org.apache.ibatis.executor.loader.javassist.JavassistSerialStateHolder -org.apache.tomcat.dbcp.dbcp.datasources.SharedPoolDataSource -org.apache.wicket.util.upload.DiskFileItem -org.apache.xalan.xsltc.trax.TemplatesImpl -org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding -org.apache.xpath.XPathContext -org.eclipse.jetty.util.log.LoggerLog -org.geotools.filter.ConstantExpression -org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator$PartiallyComparableAdvisorHolder -org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor -org.springframework.beans.factory.BeanFactory -org.springframework.beans.factory.config.PropertyPathFactoryBean -org.springframework.beans.factory.support.DefaultListableBeanFactory -org.springframework.jndi.support.SimpleJndiBeanFactory -org.springframework.orm.jpa.AbstractEntityManagerFactoryBean -org.springframework.transaction.jta.JtaTransactionManager -org.yaml.snakeyaml.tokens.DirectiveToken -sun.rmi.server.UnicastRef -javax.management.ImmutableDescriptor -org.springframework.jndi.JndiObjectTargetSource \ No newline at end of file +aj.org.objectweb.asm. +br.com.anteros. +bsh. +ch.qos.logback. +clojure. +com.alibaba.citrus.springext.support.parser. +com.alibaba.citrus.springext.util.SpringExtUtil. +com.alibaba.druid.pool. +com.alibaba.druid.stat.JdbcDataSourceStat +com.alibaba.fastjson.annotation. +com.alibaba.hotcode.internal.org.apache.commons.collections.functors. +com.alipay.custrelation.service.model.redress. +com.alipay.oceanbase.obproxy.druid.pool. +com.caucho. +com.ibatis. +com.ibm.jtc.jax.xml.bind.v2.runtime.unmarshaller. +com.ibm.xltxe.rnm1.xtq.bcel.util. +com.mchange. +com.mysql.cj.jdbc.admin. +com.mysql.cj.jdbc.MysqlConnectionPoolDataSource +com.mysql.cj.jdbc.MysqlDataSource +com.mysql.cj.jdbc.MysqlXADataSource +com.mysql.cj.log. +com.mysql.jdbc.util. +com.p6spy.engine. +com.rometools.rome.feed. +com.sun. +com.taobao.eagleeye.wrapper. +com.taobao.vipserver.commons.collections.functors. +com.zaxxer.hikari. +flex.messaging.util.concurrent. +groovy.lang. +java.awt. +java.beans. +java.io.Closeable +java.io.Serializable +java.lang.AutoCloseable +java.lang.Class +java.lang.Cloneable +java.lang.Iterable +java.lang.ProcessBuilder +java.lang.Readable +java.lang.Runnable +java.lang.Runtime +java.lang.Thread +java.lang.UNIXProcess +java.net.InetAddress +java.net.Socket +java.net.URL +java.rmi. +java.security. +java.util.EventListener +java.util.jar. +java.util.logging. +java.util.prefs. +java.util.ServiceLoader +java.util.StringTokenizer +javassist. +javax.activation. +javax.imageio. +javax.management. +javax.media.jai.remote. +javax.naming. +javax.net. +javax.print. +javax.script. +javax.sound. +javax.swing. +javax.tools. +javax.xml +jdk.internal. +jodd.db.connection. +junit. +net.bytebuddy.dynamic.loading. +net.sf.cglib. +net.sf.ehcache.hibernate. +net.sf.ehcache.transaction.manager. +ognl. +oracle.jdbc. +oracle.jms.aq. +oracle.net. +org.aoju.bus.proxy.provider. +org.apache.activemq.ActiveMQConnectionFactory +org.apache.activemq.ActiveMQXAConnectionFactory +org.apache.activemq.jms.pool. +org.apache.activemq.pool. +org.apache.activemq.spring. +org.apache.aries.transaction. +org.apache.axis2.jaxws.spi.handler. +org.apache.axis2.transport.jms. +org.apache.bcel. +org.apache.carbondata.core.scan.expression. +org.apache.catalina. +org.apache.cocoon. +org.apache.commons.beanutils. +org.apache.commons.codec. +org.apache.commons.collections.comparators. +org.apache.commons.collections.functors. +org.apache.commons.collections.Transformer +org.apache.commons.collections4.comparators. +org.apache.commons.collections4.functors. +org.apache.commons.collections4.Transformer +org.apache.commons.configuration. +org.apache.commons.configuration2. +org.apache.commons.dbcp. +org.apache.commons.fileupload. +org.apache.commons.jelly. +org.apache.commons.logging. +org.apache.commons.proxy. +org.apache.cxf.jaxrs.provider. +org.apache.hadoop.shaded.com.zaxxer.hikari. +org.apache.http.auth. +org.apache.http.conn. +org.apache.http.cookie. +org.apache.http.impl. +org.apache.ibatis.datasource. +org.apache.ibatis.executor. +org.apache.ibatis.javassist. +org.apache.ibatis.ognl. +org.apache.ibatis.parsing. +org.apache.ibatis.reflection. +org.apache.ibatis.scripting. +org.apache.ignite.cache. +org.apache.ignite.cache.jta. +org.apache.log.output.db. +org.apache.log4j. +org.apache.logging. +org.apache.myfaces.context.servlet. +org.apache.myfaces.view.facelets.el. +org.apache.openjpa.ee. +org.apache.shiro. +org.apache.tomcat. +org.apache.velocity. +org.apache.wicket.util. +org.apache.xalan. +org.apache.xbean. +org.apache.xpath. +org.apache.zookeeper. +org.aspectj. +org.codehaus.groovy.runtime. +org.codehaus.jackson. +org.datanucleus.store.rdbms.datasource.dbcp.datasources. +org.dom4j. +org.eclipse.jetty. +org.geotools.filter. +org.h2.jdbcx. +org.h2.server. +org.h2.value. +org.hibernate. +org.javasimon. +org.jaxen. +org.jboss. +org.jdom. +org.jdom2.transform. +org.junit. +org.logicalcobwebs. +org.mockito. +org.mortbay.jetty. +org.mortbay.log. +org.mozilla.javascript. +org.objectweb.asm. +org.osjava.sj. +org.python.core. +org.quartz. +org.slf4j. +org.springframework. +org.thymeleaf. +org.yaml.snakeyaml.tokens. +pstore.shaded.org.apache.commons.collections. +sun.print. +sun.rmi.server. +sun.rmi.transport. +weblogic.ejb20.internal. +weblogic.jms.common. \ No newline at end of file From 2219a4b4b9e3c4721d4011707bb6d0016c995fb8 Mon Sep 17 00:00:00 2001 From: xuqiu Date: Mon, 8 Jan 2024 20:37:20 +0800 Subject: [PATCH 13/64] =?UTF-8?q?1,=E4=BF=AE=E5=A4=8Dgson=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=AF=BC=E8=87=B4=E7=9A=84=E6=BC=8F=E6=B4=9E=20(#1358?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 殷振南 --- config/config-apollo/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config-apollo/pom.xml b/config/config-apollo/pom.xml index f3a7879a8..1e292688c 100644 --- a/config/config-apollo/pom.xml +++ b/config/config-apollo/pom.xml @@ -29,7 +29,7 @@ com.ctrip.framework.apollo apollo-client - 1.4.0 + 2.1.0 From 42d19b1b1d14a25aafd9ef7c219c04a19f90fc76 Mon Sep 17 00:00:00 2001 From: evenliu Date: Tue, 9 Jan 2024 16:22:48 +0800 Subject: [PATCH 14/64] Merge pull request from GHSA-7q8p-9953-pxvr Co-authored-by: liujianjun.ljj --- .../src/main/resources/sofa-rpc/serialize_blacklist.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt index 58269f895..ba6c18ce6 100644 --- a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt +++ b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt @@ -35,13 +35,11 @@ java.beans. java.io.Closeable java.io.Serializable java.lang.AutoCloseable -java.lang.Class java.lang.Cloneable java.lang.Iterable java.lang.ProcessBuilder java.lang.Readable java.lang.Runnable -java.lang.Runtime java.lang.Thread java.lang.UNIXProcess java.net.InetAddress From 9faa8b88ef4f51a3c7e858cb8841624ea6d8526b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:51:56 +0800 Subject: [PATCH 15/64] chore(deps): bump org.apache.dubbo:dubbo from 3.1.8 to 3.1.11 in /bom (#1381) Bumps [org.apache.dubbo:dubbo](https://github.com/apache/dubbo) from 3.1.8 to 3.1.11. - [Release notes](https://github.com/apache/dubbo/releases) - [Changelog](https://github.com/apache/dubbo/blob/3.2/CHANGES.md) - [Commits](https://github.com/apache/dubbo/compare/dubbo-3.1.8...dubbo-3.1.11) --- updated-dependencies: - dependency-name: org.apache.dubbo:dubbo dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 9a132358b..224e520fa 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -23,7 +23,7 @@ 3.5.7 4.3.0 0.22.0 - 3.1.8 + 3.1.11 2.0.3 6.3.0 1.2.2 From bd25a4e894fc7a1fde00ba15699ea3ee12aa8c16 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Tue, 9 Jan 2024 20:30:55 +0800 Subject: [PATCH 16/64] Feat/threadpool ext (#1383) * feat: refine synchronized to reentrant * feat: support thread pool extension * add lock * chore: format * chore: format * refactor: extract init method * refactor: type * fix: extension default value * fix: virtual thread constructor with config * chore: format * bump sofa common tools to 1.3.15 * chore: add test case * chore: format * chore: cr * fix:cr * cr * format lock * fix * format * refactor: method name for get executor --------- Co-authored-by: Lo1nt --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../client/AllConnectConnectionHolder.java | 5 +- .../sofa/rpc/filter/BeanIdMatchFilter.java | 9 +- .../threadpool/SofaExecutorFactory.java | 33 ++++ .../common/threadpool/ThreadPoolConstant.java | 28 ++++ .../extension/CachedThreadPoolFactory.java | 42 ++++++ .../extension/VirtualThreadPoolFactory.java | 39 +++++ .../alipay/sofa/rpc/config/ServerConfig.java | 7 +- .../dynamic/DynamicConfigManagerFactory.java | 22 ++- .../alipay/sofa/rpc/server/BusinessPool.java | 10 ++ .../sofa/rpc/server/UserThreadPool.java | 39 ++++- .../rpc/server/UserVirtualThreadPool.java | 48 ++++++ ....rpc.common.threadpool.SofaExecutorFactory | 2 + .../threadpool/ExecutorFactoryTest.java | 44 ++++++ .../rpc/config/UserThreadPoolManagerTest.java | 28 ++++ .../sofa/rpc/common/config/RpcConfigKeys.java | 10 ++ .../sofa/rpc/event/LookoutSubscriber.java | 6 +- .../rpc/metrics/lookout/RpcLookoutId.java | 33 +++- .../sofa/rpc/server/bolt/BoltServer.java | 141 ++++++++++++++---- .../rpc/server/bolt/BoltServerProcessor.java | 4 +- .../sofa/rpc/server/bolt/BoltServerTest.java | 25 ++++ 22 files changed, 522 insertions(+), 57 deletions(-) create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/SofaExecutorFactory.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/CachedThreadPoolFactory.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/server/UserVirtualThreadPool.java create mode 100644 core/api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory create mode 100644 core/api/src/test/java/com/alipay/sofa/rpc/common/threadpool/ExecutorFactoryTest.java diff --git a/all/pom.xml b/all/pom.xml index 8a88e5d43..880e138ff 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -56,7 +56,7 @@ 1.8 utf-8 1.7.21 - 1.3.2 + 1.3.15 3.29.2-GA 4.1.44.Final 3.5.2 diff --git a/bom/pom.xml b/bom/pom.xml index 224e520fa..5865f10c2 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -54,7 +54,7 @@ 4.13.1 1.6.6 - 1.3.2 + 1.3.15 3.0.8 1.4.1 diff --git a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java index 8f9a2522b..856ded84d 100644 --- a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java +++ b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java @@ -554,13 +554,16 @@ public ClientTransport getAvailableClientTransport(ProviderInfo providerInfo) { transport = uninitializedConnections.get(providerInfo); if (transport != null) { // 未初始化则初始化 - synchronized (this) { + providerLock.lock(); + try { transport = uninitializedConnections.get(providerInfo); if (transport != null) { initClientTransport(consumerConfig.getInterfaceId(), providerInfo, transport); uninitializedConnections.remove(providerInfo); } return getAvailableClientTransport(providerInfo); + } finally { + providerLock.unlock(); } } diff --git a/core-impl/filter/src/main/java/com/alipay/sofa/rpc/filter/BeanIdMatchFilter.java b/core-impl/filter/src/main/java/com/alipay/sofa/rpc/filter/BeanIdMatchFilter.java index c4c5214b1..40b14b715 100644 --- a/core-impl/filter/src/main/java/com/alipay/sofa/rpc/filter/BeanIdMatchFilter.java +++ b/core-impl/filter/src/main/java/com/alipay/sofa/rpc/filter/BeanIdMatchFilter.java @@ -21,6 +21,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * 规则id的配置形式:a,b,!c,d @@ -49,18 +51,21 @@ public abstract class BeanIdMatchFilter extends Filter { private List excludeId; private volatile boolean formatComplete; - private final Object formatLock = new Object(); + protected final Lock lock = new ReentrantLock(); @Override public boolean needToLoad(FilterInvoker invoker) { AbstractInterfaceConfig config = invoker.config; String invokerId = config.getId(); if (!formatComplete) { - synchronized (formatLock) { + lock.lock(); + try { if (!formatComplete) { formatId(idRule); formatComplete = true; } + } finally { + lock.unlock(); } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/SofaExecutorFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/SofaExecutorFactory.java new file mode 100644 index 000000000..847fe4d39 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/SofaExecutorFactory.java @@ -0,0 +1,33 @@ +/* + * 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 com.alipay.sofa.rpc.common.threadpool; + +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.Extensible; + +import java.util.concurrent.Executor; + +/** + * + * @author junyuan + * @version SofaExecutorFactory.java, v 0.1 2023年12月13日 20:02 junyuan Exp $ + */ +@Extensible +public interface SofaExecutorFactory { + + Executor createExecutor(String namePrefix, ServerConfig serverConfig); +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java new file mode 100644 index 000000000..ef9dd5b94 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java @@ -0,0 +1,28 @@ +/* + * 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 com.alipay.sofa.rpc.common.threadpool; + +/** + * + * @author junyuan + * @version ThreadPoolConstant.java, v 0.1 2023年12月12日 14:01 junyuan Exp $ + */ +public class ThreadPoolConstant { + public static final String DEFAULT_THREAD_NAME_PREFIX = "SOFA-RPC-DEFAULT"; + public static final String BIZ_THREAD_NAME_PREFIX = "SEV-BOLT-BIZ-"; + +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/CachedThreadPoolFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/CachedThreadPoolFactory.java new file mode 100644 index 000000000..06a05223a --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/CachedThreadPoolFactory.java @@ -0,0 +1,42 @@ +/* + * 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 com.alipay.sofa.rpc.common.threadpool.extension; + +import com.alipay.sofa.rpc.common.struct.NamedThreadFactory; +import com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.server.BusinessPool; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * + * @author junyuan + * @version DefaultThreadPoolFactory.java, v 0.1 2023年12月11日 20:55 junyuan Exp $ + */ +@Extension(value = "cached") +public class CachedThreadPoolFactory implements SofaExecutorFactory { + + @Override + public Executor createExecutor(String namePrefix, ServerConfig serverConfig) { + ThreadPoolExecutor executor = BusinessPool.initPool(serverConfig); + executor.setThreadFactory(new NamedThreadFactory(namePrefix, serverConfig.isDaemon())); + return executor; + } +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java new file mode 100644 index 000000000..38c293af6 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java @@ -0,0 +1,39 @@ +/* + * 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 com.alipay.sofa.rpc.common.threadpool.extension; + +import com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory; +import com.alipay.sofa.common.thread.virtual.SofaVirtualThreadFactory; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.Extension; + +import java.util.concurrent.Executor; + +/** + * + * @author junyuan + * @version VirtualThreadPoolFactory.java, v 0.1 2023年12月12日 11:11 junyuan Exp $ + */ +@Extension(value = "virtual") +public class VirtualThreadPoolFactory implements SofaExecutorFactory { + + @Override + public Executor createExecutor(String namePrefix, ServerConfig serverConfig) { + // virtual thread does not support any configs now + return SofaVirtualThreadFactory.ofExecutorService(namePrefix); + } +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/ServerConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/ServerConfig.java index e48467249..f77f7c818 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/ServerConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/ServerConfig.java @@ -16,7 +16,9 @@ */ package com.alipay.sofa.rpc.config; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.common.config.RpcConfigKeys; import com.alipay.sofa.rpc.common.utils.ExceptionUtils; import com.alipay.sofa.rpc.common.utils.NetUtils; import com.alipay.sofa.rpc.common.utils.StringUtils; @@ -96,7 +98,10 @@ public class ServerConfig extends AbstractIdConfig implements Serializable { /** * 线程池类型 */ - protected String threadPoolType = getStringValue(SERVER_POOL_TYPE); + protected String threadPoolType = SofaConfigs + .getOrCustomDefault( + RpcConfigKeys.SERVER_THREAD_POOL_TYPE /* 优先读取环境变量 */ + , getStringValue(SERVER_POOL_TYPE) /* 兜底读json配置文件 */); /** * 业务线程池大小 diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java index d4c2760c8..d3cee7245 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java @@ -25,6 +25,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * @author bystander @@ -37,6 +39,11 @@ public class DynamicConfigManagerFactory { */ private final static ConcurrentMap ALL_DYNAMICS = new ConcurrentHashMap(); + /** + * 类锁 + */ + private final static Lock classLock = new ReentrantLock(); + /** * slf4j Logger for this class */ @@ -49,13 +56,14 @@ public class DynamicConfigManagerFactory { * @param alias 别名 * @return DynamicManager 实现 */ - public static synchronized DynamicConfigManager getDynamicManager(String appName, String alias) { - if (ALL_DYNAMICS.size() > 3) { // 超过3次 是不是配错了? - if (LOGGER.isWarnEnabled()) { - LOGGER.warn("Size of dynamic manager is greater than 3, Please check it!"); - } - } + public static DynamicConfigManager getDynamicManager(String appName, String alias) { + classLock.lock(); try { + if (ALL_DYNAMICS.size() > 3) { // 超过3次 是不是配错了? + if (LOGGER.isWarnEnabled()) { + LOGGER.warn("Size of dynamic manager is greater than 3, Please check it!"); + } + } // 注意:RegistryConfig重写了equals方法,如果多个RegistryConfig属性一样,则认为是一个对象 DynamicConfigManager registry = ALL_DYNAMICS.get(alias); if (registry == null) { @@ -73,6 +81,8 @@ public static synchronized DynamicConfigManager getDynamicManager(String appName } catch (Throwable e) { throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_LOAD_EXT, "DynamicConfigManager", alias), e); + } finally { + classLock.unlock(); } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/server/BusinessPool.java b/core/api/src/main/java/com/alipay/sofa/rpc/server/BusinessPool.java index f391b6b72..ab3581ac4 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/server/BusinessPool.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/server/BusinessPool.java @@ -16,9 +16,12 @@ */ package com.alipay.sofa.rpc.server; +import com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory; import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -43,4 +46,11 @@ public static ThreadPoolExecutor initPool(ServerConfig serverConfig) { return new ThreadPoolExecutor(minPoolSize, maxPoolSize, aliveTime, TimeUnit.MILLISECONDS, poolQueue); } + public static Executor initExecutor(String executorName, ServerConfig serverConfig) { + Executor executor = ExtensionLoaderFactory.getExtensionLoader(SofaExecutorFactory.class) + .getExtension(serverConfig.getThreadPoolType()) + .createExecutor(executorName, serverConfig); + return executor; + } + } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java index 425651b6a..5eb20b539 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java @@ -19,9 +19,12 @@ import com.alipay.sofa.rpc.common.struct.NamedThreadFactory; import com.alipay.sofa.rpc.common.utils.ThreadPoolUtils; +import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * 给用户配置的自定义业务线程池 @@ -87,20 +90,30 @@ public UserThreadPool(String uniqueThreadPoolName) { /** * 线程池 */ + @Deprecated transient volatile ThreadPoolExecutor executor; + transient volatile Executor userExecutor; + + private Lock lock = new ReentrantLock(); /** * 初始化线程池 */ public void init() { - executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, + userExecutor = buildExecutor(); + } + + protected Executor buildExecutor() { + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, + TimeUnit.MILLISECONDS, ThreadPoolUtils.buildQueue(queueSize), new NamedThreadFactory(threadPoolName)); if (allowCoreThreadTimeOut) { - executor.allowCoreThreadTimeOut(true); + threadPoolExecutor.allowCoreThreadTimeOut(true); } if (prestartAllCoreThreads) { - executor.prestartAllCoreThreads(); + threadPoolExecutor.prestartAllCoreThreads(); } + return threadPoolExecutor; } /** @@ -257,14 +270,28 @@ public UserThreadPool setKeepAliveTime(int keepAliveTime) { * * @return the executor */ + @Deprecated public ThreadPoolExecutor getExecutor() { if (executor == null) { - synchronized (this) { - if (executor == null) { + Executor tmp = getUserExecutor(); + if (tmp instanceof ThreadPoolExecutor) { + executor = (ThreadPoolExecutor) tmp; + } + } + return executor; + } + + public Executor getUserExecutor() { + if (userExecutor == null) { + lock.lock(); + try { + if (userExecutor == null) { init(); } + } finally { + lock.unlock(); } } - return executor; + return userExecutor; } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/server/UserVirtualThreadPool.java b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserVirtualThreadPool.java new file mode 100644 index 000000000..e8aaeb974 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserVirtualThreadPool.java @@ -0,0 +1,48 @@ +/* + * 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 com.alipay.sofa.rpc.server; + +import com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author junyuan + * @version UserVirtualThreadPool.java, v 0.1 2023年12月14日 14:17 junyuan Exp $ + */ +public class UserVirtualThreadPool extends UserThreadPool { + private static final AtomicInteger POOL_NAME_COUNTER = new AtomicInteger(0); + + /** + * 线程名字 + * + */ + private String threadPoolName; + + public UserVirtualThreadPool() { + this.threadPoolName = DEFAUT_POOL_NAME + "-" + POOL_NAME_COUNTER.getAndIncrement(); + } + + @Override + protected Executor buildExecutor() { + return ExtensionLoaderFactory.getExtensionLoader(SofaExecutorFactory.class) + .getExtension("virtual").createExecutor(threadPoolName, null); + } +} \ No newline at end of file diff --git a/core/api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory b/core/api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory new file mode 100644 index 000000000..aac91cad5 --- /dev/null +++ b/core/api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory @@ -0,0 +1,2 @@ +cached=com.alipay.sofa.rpc.common.threadpool.extension.CachedThreadPoolFactory +virtual=com.alipay.sofa.rpc.common.threadpool.extension.VirtualThreadPoolFactory diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/common/threadpool/ExecutorFactoryTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/common/threadpool/ExecutorFactoryTest.java new file mode 100644 index 000000000..aabb5636e --- /dev/null +++ b/core/api/src/test/java/com/alipay/sofa/rpc/common/threadpool/ExecutorFactoryTest.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 com.alipay.sofa.rpc.common.threadpool; + +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * + * @author junyuan + * @version ExecutorFactoryTest.java, v 0.1 2023年12月15日 10:59 junyuan Exp $ + */ +public class ExecutorFactoryTest { + + @Test + public void testBuildCachedPool() { + ServerConfig serverConfig = new ServerConfig(); + Executor executor = ExtensionLoaderFactory.getExtensionLoader(SofaExecutorFactory.class).getExtension("cached") + .createExecutor("test", serverConfig); + Assert.assertTrue(executor instanceof ThreadPoolExecutor); + + ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; + Assert.assertEquals(threadPoolExecutor.getCorePoolSize(), serverConfig.getCoreThreads()); + } +} diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java index ddab64d26..810a61f2f 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java @@ -17,9 +17,12 @@ package com.alipay.sofa.rpc.config; import com.alipay.sofa.rpc.server.UserThreadPool; +import com.alipay.sofa.rpc.server.UserVirtualThreadPool; import org.junit.Assert; import org.junit.Test; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; public class UserThreadPoolManagerTest { @Test @@ -50,4 +53,29 @@ public void getUserThreadPoolMap() { userThreadPoolSet = UserThreadPoolManager.getUserThreadPoolSet(); Assert.assertEquals(4, userThreadPoolSet.size()); } + + @Test + public void userThreadPoolBuildTest() { + UserThreadPool userThreadPool = new UserVirtualThreadPool(); + Object result; + try { + result = userThreadPool.getExecutor(); + } catch (UnsupportedOperationException e) { + // jdk 21 以下, 这里应该抛出 UnsupportedOperationException + return; + } + Assert.assertNull(result); + } + + @Test + public void userThreadPoolCompatibleTest() { + UserThreadPool userThreadPool = new UserThreadPool(); + Object result; + result = userThreadPool.getExecutor(); + Assert.assertNotNull(result); + Executor executorService = userThreadPool.getUserExecutor(); + Assert.assertTrue(executorService instanceof ThreadPoolExecutor); + + Assert.assertEquals(executorService, result); + } } \ No newline at end of file diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java index bba581abf..2b4934ce0 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java @@ -130,4 +130,14 @@ public class RpcConfigKeys { " The default filtering mode is STRICT.You can also set WARN or DISABLE", new String[] { "sofa_rpc_codec_serialize_checkMode" }); + /** + * biz thread pool type + */ + public static ConfigKey SERVER_THREAD_POOL_TYPE = ConfigKey + .build( + "sofa.rpc.server.thread.pool.type", + "cached", + false, + "specify biz thread pool implementation type", + new String[] { "sofa_rpc_server_thread_pool_type" }); } diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java index 39b107872..51f292f92 100644 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java +++ b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java @@ -78,8 +78,10 @@ public void onEvent(Event event) { ServerStartedEvent serverStartedEvent = (ServerStartedEvent) event; - rpcMetrics.collectThreadPool(serverStartedEvent.getServerConfig(), - serverStartedEvent.getThreadPoolExecutor()); + if (serverStartedEvent.getThreadPoolExecutor() != null) { + rpcMetrics.collectThreadPool(serverStartedEvent.getServerConfig(), + serverStartedEvent.getThreadPoolExecutor()); + } } else if (eventClass == ServerStoppedEvent.class) { ServerStoppedEvent serverStartedEvent = (ServerStoppedEvent) event; diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java index f7642adfe..e9d406d78 100644 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java +++ b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java @@ -23,6 +23,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * @author LiWei.Liangen @@ -36,10 +38,12 @@ public class RpcLookoutId { private final ConcurrentMap serverConfigIds = new ConcurrentHashMap(); private volatile Id consumerConfigId; - private final Object consumerConfigIdLock = new Object(); private volatile Id providerConfigId; - private final Object providerConfigIdLock = new Object(); + + private static final Lock classLock = new ReentrantLock(); + private final Lock consumerConfigIdLock = new ReentrantLock(); + private final Lock providerConfigIdLock = new ReentrantLock(); /** * create consumerId @@ -51,12 +55,15 @@ public Id fetchConsumerStatId(Map tags) { String key = tags.toString(); Id lookoutId = consumerIds.get(key); if (lookoutId == null) { - synchronized (RpcLookoutId.class) { + classLock.lock(); + try { lookoutId = consumerIds.get(key); if (lookoutId == null) { lookoutId = Lookout.registry().createId("rpc.consumer.service.stats", tags); consumerIds.put(key, lookoutId); } + } finally { + classLock.unlock(); } } return lookoutId; @@ -71,12 +78,15 @@ public Id fetchProviderStatId(Map tags) { String key = tags.toString(); Id lookoutId = providerIds.get(key); if (lookoutId == null) { - synchronized (RpcLookoutId.class) { + classLock.lock(); + try { lookoutId = providerIds.get(key); if (lookoutId == null) { lookoutId = Lookout.registry().createId("rpc.provider.service.stats", tags); providerIds.put(key, lookoutId); } + } finally { + classLock.unlock(); } } return lookoutId; @@ -84,10 +94,13 @@ public Id fetchProviderStatId(Map tags) { public Id fetchConsumerSubId() { if (consumerConfigId == null) { - synchronized (consumerConfigIdLock) { + consumerConfigIdLock.lock(); + try { if (consumerConfigId == null) { consumerConfigId = Lookout.registry().createId("rpc.consumer.info.stats"); } + } finally { + consumerConfigIdLock.unlock(); } } return consumerConfigId; @@ -95,10 +108,13 @@ public Id fetchConsumerSubId() { public Id fetchProviderPubId() { if (providerConfigId == null) { - synchronized (providerConfigIdLock) { + providerConfigIdLock.lock(); + try { if (providerConfigId == null) { providerConfigId = Lookout.registry().createId("rpc.provider.info.stats"); } + } finally { + providerConfigIdLock.unlock(); } } return providerConfigId; @@ -127,12 +143,15 @@ public Id fetchServerThreadPoolQueueSizeId(ServerConfig serverConfig) { private Id fetchServerConfigId(String key) { Id lookoutId = serverConfigIds.get(key); if (lookoutId == null) { - synchronized (RpcLookout.class) { + classLock.lock(); + try { lookoutId = serverConfigIds.get(key); if (lookoutId == null) { lookoutId = Lookout.registry().createId(key); serverConfigIds.put(key, lookoutId); } + } finally { + classLock.unlock(); } } return lookoutId; diff --git a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServer.java b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServer.java index d1b9cec9d..3a054d98c 100644 --- a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServer.java +++ b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServer.java @@ -20,6 +20,7 @@ import com.alipay.remoting.rpc.RpcServer; import com.alipay.sofa.rpc.common.cache.ReflectCache; import com.alipay.sofa.rpc.common.struct.NamedThreadFactory; +import com.alipay.sofa.rpc.common.threadpool.ThreadPoolConstant; import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; import com.alipay.sofa.rpc.config.ProviderConfig; import com.alipay.sofa.rpc.config.ServerConfig; @@ -40,6 +41,8 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicInteger; @@ -75,8 +78,14 @@ public class BoltServer implements Server { /** * 业务线程池 */ + @Deprecated protected ThreadPoolExecutor bizThreadPool; + /** + * 业务线程池, 也支持非池化的执行器 + */ + protected Executor bizExecutor; + /** * Invoker列表,接口--> Invoker */ @@ -85,20 +94,37 @@ public class BoltServer implements Server { @Override public void init(ServerConfig serverConfig) { this.serverConfig = serverConfig; - // 启动线程池 - bizThreadPool = initThreadPool(serverConfig); + bizExecutor = initExecutor(serverConfig); + if (bizExecutor instanceof ThreadPoolExecutor) { + bizThreadPool = (ThreadPoolExecutor) bizExecutor; + } boltServerProcessor = new BoltServerProcessor(this); } - protected ThreadPoolExecutor initThreadPool(ServerConfig serverConfig) { - ThreadPoolExecutor threadPool = BusinessPool.initPool(serverConfig); - threadPool.setThreadFactory(new NamedThreadFactory( - "SEV-BOLT-BIZ-" + serverConfig.getPort(), serverConfig.isDaemon())); - threadPool.setRejectedExecutionHandler(new SofaRejectedExecutionHandler()); + /** + * 指定类型初始化线程池 + * @param serverConfig + * @return + */ + protected Executor initExecutor(ServerConfig serverConfig) { + Executor executor = BusinessPool.initExecutor( + ThreadPoolConstant.BIZ_THREAD_NAME_PREFIX + serverConfig.getPort(), serverConfig); + if (executor instanceof ThreadPoolExecutor) { + configureThreadPoolExecutor((ThreadPoolExecutor) executor, serverConfig); + } + return executor; + } + + /** + * 针对 ThreadPoolExecutor 进行额外配置 + * @param executor + * @param serverConfig + */ + protected void configureThreadPoolExecutor(ThreadPoolExecutor executor, ServerConfig serverConfig) { + executor.setRejectedExecutionHandler(new SofaRejectedExecutionHandler()); if (serverConfig.isPreStartCore()) { // 初始化核心线程池 - threadPool.prestartAllCoreThreads(); + executor.prestartAllCoreThreads(); } - return threadPool; } @Override @@ -204,28 +230,73 @@ public void destroy() { return; } int stopTimeout = serverConfig.getStopTimeout(); - if (stopTimeout > 0) { // 需要等待结束时间 - AtomicInteger count = boltServerProcessor.processingCount; - // 有正在执行的请求 或者 队列里有请求 - if (count.get() > 0 || bizThreadPool.getQueue().size() > 0) { - long start = RpcRuntimeContext.now(); - if (LOGGER.isInfoEnabled()) { - LOGGER.info("There are {} call in processing and {} call in queue, wait {} ms to end", - count, bizThreadPool.getQueue().size(), stopTimeout); - } - while ((count.get() > 0 || bizThreadPool.getQueue().size() > 0) - && RpcRuntimeContext.now() - start < stopTimeout) { // 等待返回结果 - try { - Thread.sleep(10); - } catch (InterruptedException ignore) { - } + destroyThreadPool(bizExecutor, stopTimeout); + stop(); + } + + /** + * 如果未设置有效的 stopWaitTime, 将直接触发 shutdown + * @param executor + * @param stopWaitTime + */ + private void destroyThreadPool(Executor executor, int stopWaitTime) { + if (stopWaitTime > 0) { + if (executor instanceof ThreadPoolExecutor) { + threadPoolExecutorDestroy((ThreadPoolExecutor) executor, stopWaitTime); + } else if (executor instanceof ExecutorService) { + executorServiceDestroy((ExecutorService) executor, stopWaitTime); + } + } + } + + /** + * 将在 stopWaitTime 时限到期时强制 shutdown + * @param executor + * @param stopWaitTime + */ + private void threadPoolExecutorDestroy(ThreadPoolExecutor executor, int stopWaitTime) { + AtomicInteger count = boltServerProcessor.processingCount; + // 有正在执行的请求 或者 队列里有请求 + if (count.get() > 0 || executor.getQueue().size() > 0) { + long start = RpcRuntimeContext.now(); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("There are {} call in processing and {} call in queue, wait {} ms to end", + count, executor.getQueue().size(), stopWaitTime); + } + while ((count.get() > 0 || executor.getQueue().size() > 0) + && RpcRuntimeContext.now() - start < stopWaitTime) { // 等待返回结果 + try { + Thread.sleep(10); + } catch (InterruptedException ignore) { } - } // 关闭前检查已有请求? + } } + executor.shutdown(); + } - // 关闭线程池 - bizThreadPool.shutdown(); - stop(); + /** + * 针对 ExecutorService, shutdown 后仍然会处理 queue 内任务, 不用判断 queue + * @param executorService + * @param stopWaitTime + */ + private void executorServiceDestroy(ExecutorService executorService, int stopWaitTime) { + AtomicInteger count = boltServerProcessor.processingCount; + // 有正在执行的请求 或者 队列里有请求 + if (count.get() > 0) { + long start = RpcRuntimeContext.now(); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("There are {} call in processing, wait {} ms to end", + count, stopWaitTime); + } + while ((count.get() > 0) + && RpcRuntimeContext.now() - start < stopWaitTime) { // 等待返回结果 + try { + Thread.sleep(10); + } catch (InterruptedException ignore) { + } + } + } + executorService.shutdown(); } @Override @@ -244,10 +315,15 @@ public void destroy(DestroyHook hook) { * * @return 业务线程池 */ + @Deprecated public ThreadPoolExecutor getBizThreadPool() { return bizThreadPool; } + public Executor getBizExecutor() { + return bizExecutor; + } + /** * 找到服务端Invoker * @@ -269,4 +345,13 @@ public void cleanReflectCache(ProviderConfig providerConfig) { ReflectCache.invalidateMethodSigsCache(key); ReflectCache.invalidateOverloadMethodCache(key); } + + @Deprecated + protected ThreadPoolExecutor initThreadPool(ServerConfig serverConfig) { + ThreadPoolExecutor threadPool = BusinessPool.initPool(serverConfig); + threadPool.setThreadFactory(new NamedThreadFactory( + ThreadPoolConstant.BIZ_THREAD_NAME_PREFIX + serverConfig.getPort(), serverConfig.isDaemon())); + configureThreadPoolExecutor(threadPool, serverConfig); + return threadPool; + } } diff --git a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java index e03563614..5939d7683 100644 --- a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java +++ b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java @@ -332,7 +332,7 @@ public String interest() { @Override public Executor getExecutor() { - return boltServer.getBizThreadPool(); + return boltServer.getBizExecutor(); } @Override @@ -361,7 +361,7 @@ public Executor select(String requestClass, Object requestHeader) { if (service != null) { UserThreadPool threadPool = UserThreadPoolManager.getUserThread(service); if (threadPool != null) { - Executor executor = threadPool.getExecutor(); + Executor executor = threadPool.getUserExecutor(); if (executor != null) { // 存在自定义线程池,且不为空 return executor; diff --git a/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/server/bolt/BoltServerTest.java b/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/server/bolt/BoltServerTest.java index 148cd6b00..066aa89ad 100644 --- a/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/server/bolt/BoltServerTest.java +++ b/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/server/bolt/BoltServerTest.java @@ -75,4 +75,29 @@ public void start() throws Exception { server.destroy(); } + @Test + public void threadPoolDestroyTest() { + String host = "127.0.0.1"; + int port = 17702; + ServerConfig serverConfig = new ServerConfig(); + serverConfig.setBoundHost(host); + serverConfig.setPort(port); + serverConfig.setProtocol(RpcConstants.PROTOCOL_TYPE_BOLT); + + BoltServer server = new BoltServer(); + server.init(serverConfig); + server.start(); + Assert.assertTrue(server.started); + Assert.assertTrue(NetUtils.canTelnet(host, port, 1000)); + + server.destroy(); + } + + @Test + public void testDeprecatedInitThreadExecutor() { + BoltServer server = new BoltServer(); + server.initThreadPool(new ServerConfig()); + server.destroy(); + } + } \ No newline at end of file From a12fa206ad94ac8db66146bca1c6c47d2436448a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 20:33:18 +0800 Subject: [PATCH 17/64] chore(deps): bump ch.qos.logback:logback-classic in /bom (#1379) Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.2.3 to 1.2.13. - [Commits](https://github.com/qos-ch/logback/compare/v_1.2.3...v_1.2.13) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 5865f10c2..729329162 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -49,7 +49,7 @@ 2.12.1 1.7.21 - 1.2.3 + 1.2.13 4.13.1 From f48412c7f8c6d9547ad37781360616ff17c9b978 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Fri, 12 Jan 2024 15:06:01 +0800 Subject: [PATCH 18/64] add dep fury (#1387) * add dep fury * enhance fury codec exception --------- Co-authored-by: Lo1nt Co-authored-by: liujianjun.ljj --- all/pom.xml | 6 +++++ .../sofa/rpc/codec/fury/FurySerializer.java | 15 +++++-------- .../serialize/SofaRequestFurySerializer.java | 21 +++++++++--------- .../serialize/SofaResponseFurySerializer.java | 22 +++++++++---------- .../sofa/rpc/codec/AbstractSerializer.java | 8 +++---- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 880e138ff..c4ce304bb 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -73,6 +73,7 @@ 1.53.0 32.0.0-jre 2.12.1 + 0.4.1 @@ -434,6 +435,11 @@ asm ${asm.version} + + org.furyio + fury-core + ${fury.version} + diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java index e1a61a6fd..3f8980623 100644 --- a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java @@ -32,6 +32,7 @@ import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; import io.fury.Fury; import io.fury.ThreadLocalFury; +import io.fury.ThreadSafeFury; import io.fury.config.Language; import io.fury.memory.MemoryBuffer; import io.fury.resolver.AllowListChecker; @@ -47,9 +48,9 @@ @Extension(value = "fury2", code = 22) public class FurySerializer extends AbstractSerializer { - private final ThreadLocalFury fury; + protected final ThreadSafeFury fury; - private final String checkerMode = SofaConfigs.getOrDefault(RpcConfigKeys.SERIALIZE_CHECKER_MODE); + private final String checkerMode = SofaConfigs.getOrDefault(RpcConfigKeys.SERIALIZE_CHECKER_MODE); public FurySerializer() { fury = new ThreadLocalFury(classLoader -> { @@ -102,8 +103,8 @@ public FurySerializer() { f.register(SofaRpcException.class); return f; }); - addSerializer(SofaRequest.class, new SofaRequestFurySerializer(fury)); - addSerializer(SofaResponse.class, new SofaResponseFurySerializer(fury)); + addCustomSerializer(SofaRequest.class, new SofaRequestFurySerializer(fury)); + addCustomSerializer(SofaResponse.class, new SofaResponseFurySerializer(fury)); } @Override @@ -139,7 +140,7 @@ public Object decode(final AbstractByteBuf data, final Class clazz, final Map { - private final ThreadLocalFury fury; + private final ThreadSafeFury fury; - public SofaRequestFurySerializer(ThreadLocalFury fury) { + public SofaRequestFurySerializer(ThreadSafeFury fury) { this.fury = fury; } @@ -51,7 +52,7 @@ public AbstractByteBuf encodeObject(SofaRequest object, Map cont isGenericRequest(context.get(RemotingConstants.HEAD_GENERIC_TYPE)); if (genericSerialize) { // TODO support generic call - throw new SofaRpcException("Generic call is not supported for now."); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Generic call is not supported for now."); } fury.serialize(writeBuffer, object); final Object[] args = object.getMethodArgs(); @@ -59,7 +60,7 @@ public AbstractByteBuf encodeObject(SofaRequest object, Map cont return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, e.getMessage(), e); } } @@ -70,7 +71,7 @@ public SofaRequest decodeObject(AbstractByteBuf data, Map contex SofaRequest sofaRequest = (SofaRequest) fury.deserialize(readBuffer); String targetServiceName = sofaRequest.getTargetServiceUniqueName(); if (targetServiceName == null) { - throw new SofaRpcException("Target service name of request is null!"); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, "Target service name of request is null!"); } String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName); sofaRequest.setInterfaceName(interfaceName); @@ -78,7 +79,7 @@ public SofaRequest decodeObject(AbstractByteBuf data, Map contex sofaRequest.setMethodArgs(args); return sofaRequest; } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, e.getMessage(), e); } } @@ -86,14 +87,14 @@ public SofaRequest decodeObject(AbstractByteBuf data, Map contex public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaRequest template) throws SofaRpcException { if (data.readableBytes() <= 0) { - throw new SofaRpcException("Deserialized array is empty."); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, "Deserialized array is empty."); } try { MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); SofaRequest tmp = (SofaRequest) fury.deserialize(readBuffer); String targetServiceName = tmp.getTargetServiceUniqueName(); if (targetServiceName == null) { - throw new SofaRpcException("Target service name of request is null!"); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, "Target service name of request is null!"); } // copy values to template template.setMethodName(tmp.getMethodName()); @@ -106,7 +107,7 @@ public void decodeObjectByTemplate(AbstractByteBuf data, Map con final Object[] args = (Object[]) fury.deserialize(readBuffer); template.setMethodArgs(args); } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, e.getMessage(), e); } } diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java index 9a7402ab1..5983be113 100644 --- a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java +++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java @@ -18,11 +18,12 @@ import com.alipay.sofa.rpc.codec.CustomSerializer; import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.core.exception.RpcErrorType; import com.alipay.sofa.rpc.core.exception.SofaRpcException; import com.alipay.sofa.rpc.core.response.SofaResponse; import com.alipay.sofa.rpc.transport.AbstractByteBuf; import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; -import io.fury.ThreadLocalFury; +import io.fury.ThreadSafeFury; import io.fury.memory.MemoryBuffer; import java.util.Map; @@ -33,22 +34,21 @@ */ public class SofaResponseFurySerializer implements CustomSerializer { - private final ThreadLocalFury fury; + private final ThreadSafeFury fury; - public SofaResponseFurySerializer(ThreadLocalFury fury) { + public SofaResponseFurySerializer(ThreadSafeFury fury) { this.fury = fury; } @Override public AbstractByteBuf encodeObject(SofaResponse object, Map context) throws SofaRpcException { try { - fury.setClassLoader(Thread.currentThread().getContextClassLoader()); MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32); writeBuffer.writerIndex(0); fury.serialize(writeBuffer, object); return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex())); } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.SERVER_DESERIALIZE, e.getMessage(), e); } } @@ -56,16 +56,15 @@ public AbstractByteBuf encodeObject(SofaResponse object, Map con public SofaResponse decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException { MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); try { - fury.setClassLoader(Thread.currentThread().getContextClassLoader()); boolean genericSerialize = context != null && isGenericResponse( context.get(RemotingConstants.HEAD_GENERIC_TYPE)); if (genericSerialize) { // TODO support generic call - throw new SofaRpcException("Generic call is not supported for now."); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Generic call is not supported for now."); } return (SofaResponse) fury.deserialize(readBuffer); } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, e.getMessage(), e); } } @@ -73,17 +72,16 @@ public SofaResponse decodeObject(AbstractByteBuf data, Map conte public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaResponse template) throws SofaRpcException { if (data.readableBytes() <= 0) { - throw new SofaRpcException("Deserialized array is empty."); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Deserialized array is empty."); } try { - fury.setClassLoader(Thread.currentThread().getContextClassLoader()); MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array()); // 根据SerializeType信息决定序列化器 boolean genericSerialize = context != null && isGenericResponse( context.get(RemotingConstants.HEAD_GENERIC_TYPE)); if (genericSerialize) { // TODO support generic call - throw new SofaRpcException("Generic call is not supported for now."); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Generic call is not supported for now."); } else { SofaResponse tmp = (SofaResponse) fury.deserialize(readBuffer); // copy values to template @@ -92,7 +90,7 @@ public void decodeObjectByTemplate(AbstractByteBuf data, Map con template.setResponseProps(tmp.getResponseProps()); } } catch (Exception e) { - throw new SofaRpcException(e.getMessage(), e); + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, e.getMessage(), e); } } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java index efe20c953..3c3a0b378 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java @@ -76,18 +76,18 @@ public static void clear() { genericServiceMap.clear(); } - protected CustomSerializer getObjCustomSerializer(Object obj) { + protected CustomSerializer getObjCustomSerializer(Object obj) { if (obj == null) { return null; } - return getSerializer(obj.getClass()); + return getCustomSerializer(obj.getClass()); } - protected CustomSerializer getSerializer(Class clazz) { + protected CustomSerializer getCustomSerializer(Class clazz) { return customSerializers.get(clazz); } - protected void addSerializer(Class clazz, CustomSerializer serializerManager) { + public void addCustomSerializer(Class clazz, CustomSerializer serializerManager) { customSerializers.put(clazz, serializerManager); } } From 98a9b715d5c7601b4ddcb6831b5d872c0ee88a58 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 15 Jan 2024 20:41:35 +0800 Subject: [PATCH 19/64] feat: support jackson config (#1388) * feat: support jackson config * fix: ut * format code * fix: cr * format --------- Co-authored-by: Lo1nt --- .../rpc/codec/jackson/JacksonConfigKeys.java | 58 ++++++++++ .../rpc/codec/jackson/JacksonSerializer.java | 109 ++++++++++++++---- .../codec/jackson/JacksonSerializerTest.java | 66 +++++++++++ 3 files changed, 213 insertions(+), 20 deletions(-) create mode 100644 codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonConfigKeys.java diff --git a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonConfigKeys.java b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonConfigKeys.java new file mode 100644 index 000000000..4ecd3e836 --- /dev/null +++ b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonConfigKeys.java @@ -0,0 +1,58 @@ +/* + * 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 com.alipay.sofa.rpc.codec.jackson; + +import com.alipay.sofa.common.config.ConfigKey; + +/** + * + * @author junyuan + * @version JacksonConfigKeys.java, v 0.1 2024-01-15 16:46 junyuan Exp $ + */ +public class JacksonConfigKeys { + public static ConfigKey JACKSON_SER_FEATURE_ENABLE_LIST = ConfigKey + .build( + "sofa.rpc.codec.jackson.serialize.feature.enable.list", + "", + false, + "serialize feature to enable", + new String[] { "sofa_rpc_codec_jackson_serialize_feature_enable_list" }); + + public static ConfigKey JACKSON_SER_FEATURE_DISABLE_LIST = ConfigKey + .build( + "sofa.rpc.codec.jackson.serialize.feature.disable.list", + "", + false, + "serialize feature to disable", + new String[] { "sofa_rpc_codec_jackson_serialize_feature_disable_list" }); + + public static ConfigKey JACKSON_DES_FEATURE_ENABLE_LIST = ConfigKey + .build( + "sofa.rpc.codec.jackson.deserialize.feature.enable.list", + "", + false, + "deserialize feature to enable", + new String[] { "sofa_rpc_codec_jackson_deserialize_feature_disable_list" }); + + public static ConfigKey JACKSON_DES_FEATURE_DISABLE_LIST = ConfigKey + .build( + "sofa.rpc.codec.jackson.deserialize.feature.disable.list", + "", + false, + "deserialize feature to disable", + new String[] { "sofa_rpc_codec_jackson_deserialize_feature_disable_list" }); +} \ No newline at end of file diff --git a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java index db7e593df..66ebb5741 100644 --- a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java +++ b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java @@ -16,8 +16,11 @@ */ package com.alipay.sofa.rpc.codec.jackson; +import com.alipay.sofa.common.config.ConfigKey; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.codec.AbstractSerializer; import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.common.annotation.VisibleForTesting; import com.alipay.sofa.rpc.common.utils.CodecUtils; import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; @@ -37,10 +40,13 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; /** * Json serializer. @@ -64,39 +70,96 @@ @Extension(value = "json", code = 12) public class JacksonSerializer extends AbstractSerializer { - private ObjectMapper mapper = new ObjectMapper(); + private ObjectMapper mapper = new ObjectMapper(); - private JacksonHelper jacksonHelper = new JacksonHelper(); + private JacksonHelper jacksonHelper = new JacksonHelper(); - private static final String DESERIALIZATIONFEATURE_PREFIX = "sofa.rpc.codec.jackson.DeserializationFeature."; + @Deprecated + private static final String DESERIALIZATION_FEATURE_PREFIX = "sofa.rpc.codec.jackson.DeserializationFeature."; - private static final String SERIALIZATIONFEATURE_PREFIX = "sofa.rpc.codec.jackson.SerializationFeature."; + @Deprecated + private static final String SERIALIZATION_FEATURE_PREFIX = "sofa.rpc.codec.jackson.SerializationFeature."; + /** + * two ways to config: + *
    + *
  1. the new config read from env or vm args sofa.rpc.codec.jackson.serialize.feature.enable.list=FAIL_ON_EMPTY_BEANS,FAIL_ON_NULL_FOR_PRIMITIVES
  2. + *
  3. the deprecated config sofa.rpc.codec.jackson.DeserializationFeature.FAIL_ON_EMPTY_BEANS=true
  4. + *
+ */ public JacksonSerializer() { + Set serFeatures = Arrays.stream(SerializationFeature.values()).map(Enum::name).collect(Collectors.toSet()); + Set desFeatures = Arrays.stream(DeserializationFeature.values()).map(Enum::name).collect(Collectors.toSet()); + Properties properties = System.getProperties(); for (String key : properties.stringPropertyNames()) { - if (key.startsWith(DESERIALIZATIONFEATURE_PREFIX)) { - String enumName = StringUtils.substringAfter(key, DESERIALIZATIONFEATURE_PREFIX); - for (DeserializationFeature df : DeserializationFeature.values()) { - if (df.name().equals(enumName)) { - boolean state = Boolean.parseBoolean(properties.getProperty(key)); - mapper.configure(df, state); - break; - } + if (key.startsWith(DESERIALIZATION_FEATURE_PREFIX)) { + String enumName = StringUtils.substringAfter(key, DESERIALIZATION_FEATURE_PREFIX); + if (desFeatures.contains(enumName)) { + boolean state = Boolean.parseBoolean(properties.getProperty(key)); + mapper.configure(DeserializationFeature.valueOf(enumName), state); } } - if (key.startsWith(SERIALIZATIONFEATURE_PREFIX)) { - String enumName = StringUtils.substringAfter(key, SERIALIZATIONFEATURE_PREFIX); - for (SerializationFeature sf : SerializationFeature.values()) { - if (sf.name().equals(enumName)) { - boolean state = Boolean.parseBoolean(properties.getProperty(key)); - mapper.configure(sf, state); - break; - } + if (key.startsWith(SERIALIZATION_FEATURE_PREFIX)) { + String enumName = StringUtils.substringAfter(key, SERIALIZATION_FEATURE_PREFIX); + if (serFeatures.contains(enumName)) { + boolean state = Boolean.parseBoolean(properties.getProperty(key)); + mapper.configure(SerializationFeature.valueOf(enumName), state); } } } + + // 允许通过 sofa config 获取的配置覆盖上述环境变量配置 + processJacksonSerFeature(mapper, serFeatures, desFeatures); + } + + /** + * + * @param objectMapper + * @param serFeatures + * @param desFeatures + */ + protected void processJacksonSerFeature(ObjectMapper objectMapper, Set serFeatures, Set desFeatures) { + processSerializeFeatures(objectMapper, JacksonConfigKeys.JACKSON_SER_FEATURE_ENABLE_LIST, true, serFeatures); + processSerializeFeatures(objectMapper, JacksonConfigKeys.JACKSON_SER_FEATURE_DISABLE_LIST, false, serFeatures); + + processDeserializeFeatures(objectMapper, JacksonConfigKeys.JACKSON_DES_FEATURE_ENABLE_LIST, true, desFeatures); + processDeserializeFeatures(objectMapper, JacksonConfigKeys.JACKSON_DES_FEATURE_DISABLE_LIST, false, desFeatures); + } + + /** + * 获取用户配置的 feature, 应该是逗号分割的 string + * 根据 String 获取对应的 SerializationFeature, 并配置到 object mapper + * + * @param objectMapper + * @param key + * @param enable + * @param featureSet + */ + private void processSerializeFeatures(ObjectMapper objectMapper, ConfigKey key, boolean enable, Set featureSet) { + String serFeatureList = SofaConfigs.getOrDefault(key); + if (StringUtils.isBlank(serFeatureList)) { + return; + } + Arrays.stream(serFeatureList.split(",")).filter(featureSet::contains).forEach(str -> objectMapper.configure(SerializationFeature.valueOf(str), enable)); + } + + /** + * 获取用户配置的 feature, 应该是逗号分割的 string + * 根据 String 获取对应的 DeserializationFeature, 并配置到 object mapper + * + * @param objectMapper + * @param key + * @param enable + * @param featureSet + */ + private void processDeserializeFeatures(ObjectMapper objectMapper,ConfigKey key, boolean enable, Set featureSet) { + String desFeatureList = SofaConfigs.getOrDefault(key); + if (StringUtils.isBlank(desFeatureList)) { + return; + } + Arrays.stream(desFeatureList.split(",")).filter(featureSet::contains).forEach(str -> objectMapper.configure(DeserializationFeature.valueOf(str), enable)); } @Override @@ -326,4 +389,10 @@ private void decodeSofaResponse(AbstractByteBuf data, SofaResponse sofaResponse, sofaResponse.setAppResponse(result); } } + + @VisibleForTesting + protected ObjectMapper getMapper() { + return this.mapper; + } + } diff --git a/codec/codec-jackson/src/test/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializerTest.java b/codec/codec-jackson/src/test/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializerTest.java index eb4f84992..be218792a 100644 --- a/codec/codec-jackson/src/test/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializerTest.java +++ b/codec/codec-jackson/src/test/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializerTest.java @@ -33,7 +33,9 @@ import com.alipay.sofa.rpc.core.response.SofaResponse; import com.alipay.sofa.rpc.transport.AbstractByteBuf; import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import org.junit.Assert; import org.junit.Test; @@ -504,6 +506,70 @@ public void testJacksonFeature() throws UnsupportedEncodingException { } + @Test + public void testJacksonFeatureByConfigKey() { + // origin, should be FAIL_ON_UNKNOWN_PROPERTIES ture and FAIL_ON_EMPTY_BEANS true + JacksonSerializer origin = new JacksonSerializer(); + ObjectMapper originMapper = origin.getMapper(); + // originally false + Assert.assertFalse(originMapper.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)); + Assert.assertFalse(originMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)); + + // originally true + Assert.assertTrue(originMapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); + Assert.assertTrue(originMapper.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES)); + + // originally false + Assert.assertFalse(originMapper.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)); + Assert.assertFalse(originMapper.isEnabled(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)); + + // originally true + Assert.assertTrue(originMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)); + Assert.assertTrue(originMapper.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)); + + JacksonSerializer testSer = null; + try { + System.setProperty(JacksonConfigKeys.JACKSON_SER_FEATURE_ENABLE_LIST.getKey(), + SerializationFeature.WRAP_ROOT_VALUE + "," + + SerializationFeature.INDENT_OUTPUT); + System.setProperty(JacksonConfigKeys.JACKSON_SER_FEATURE_DISABLE_LIST.getKey(), + SerializationFeature.FAIL_ON_EMPTY_BEANS.name() + "," + + SerializationFeature.FAIL_ON_SELF_REFERENCES.name()); + System.setProperty(JacksonConfigKeys.JACKSON_DES_FEATURE_ENABLE_LIST.getKey(), + DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES + "," + + DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS); + System.setProperty(JacksonConfigKeys.JACKSON_DES_FEATURE_DISABLE_LIST.getKey(), + DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.name() + "," + + DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS.name()); + // test ser after property set + testSer = new JacksonSerializer(); + + } finally { + System.clearProperty(JacksonConfigKeys.JACKSON_SER_FEATURE_ENABLE_LIST.getKey()); + System.clearProperty(JacksonConfigKeys.JACKSON_SER_FEATURE_DISABLE_LIST.getKey()); + System.clearProperty(JacksonConfigKeys.JACKSON_DES_FEATURE_ENABLE_LIST.getKey()); + System.clearProperty(JacksonConfigKeys.JACKSON_DES_FEATURE_DISABLE_LIST.getKey()); + } + + ObjectMapper testMapper = testSer.getMapper(); + + // originally false, but enabled + Assert.assertTrue(testMapper.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)); + Assert.assertTrue(testMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)); + + // originally true, but disabled + Assert.assertFalse(testMapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); + Assert.assertFalse(testMapper.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES)); + + // originally false, but enabled + Assert.assertTrue(testMapper.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)); + Assert.assertTrue(testMapper.isEnabled(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)); + + // originally true, but disabled + Assert.assertFalse(testMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)); + Assert.assertFalse(testMapper.isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)); + } + @Test(expected = ClassCastException.class) public void testGenericSofaRequestFail() throws Exception { AbstractSerializer.clear(); From ff333d3e101be89fcd92f3c63d6a0629950cb1a6 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 22 Jan 2024 10:43:09 +0800 Subject: [PATCH 20/64] chore: virtual thread name (#1393) Co-authored-by: Lo1nt --- .../common/threadpool/ThreadPoolConstant.java | 4 +++ .../extension/VirtualThreadPoolFactory.java | 26 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java index ef9dd5b94..5a040640b 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/ThreadPoolConstant.java @@ -25,4 +25,8 @@ public class ThreadPoolConstant { public static final String DEFAULT_THREAD_NAME_PREFIX = "SOFA-RPC-DEFAULT"; public static final String BIZ_THREAD_NAME_PREFIX = "SEV-BOLT-BIZ-"; + public static final String TYPE_PREFIX_TREAD = "T"; + + public static final String TYPE_PREFIX_VIRTUAL_TREAD = "VT"; + } diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java index 38c293af6..a16e835b0 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/threadpool/extension/VirtualThreadPoolFactory.java @@ -18,10 +18,12 @@ import com.alipay.sofa.rpc.common.threadpool.SofaExecutorFactory; import com.alipay.sofa.common.thread.virtual.SofaVirtualThreadFactory; +import com.alipay.sofa.rpc.common.threadpool.ThreadPoolConstant; import com.alipay.sofa.rpc.config.ServerConfig; import com.alipay.sofa.rpc.ext.Extension; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; /** * @@ -31,9 +33,31 @@ @Extension(value = "virtual") public class VirtualThreadPoolFactory implements SofaExecutorFactory { + /** + * 系统全局线程池计数器 + */ + private static final AtomicInteger POOL_COUNT = new AtomicInteger(); + @Override public Executor createExecutor(String namePrefix, ServerConfig serverConfig) { // virtual thread does not support any configs now - return SofaVirtualThreadFactory.ofExecutorService(namePrefix); + return SofaVirtualThreadFactory.ofExecutorService(buildNamePrefix(namePrefix)); + } + + /** + * refine virtual thread name + * SOFA-originInput-0-VT123 + * @param namePrefix + * @return + */ + private String buildNamePrefix(String namePrefix) { + StringBuilder sb = new StringBuilder(); + sb.append("SOFA-"); + sb.append(namePrefix); + sb.append("-"); + sb.append(POOL_COUNT.getAndIncrement()); + sb.append("-"); + sb.append(ThreadPoolConstant.TYPE_PREFIX_VIRTUAL_TREAD); + return sb.toString(); } } From f37465bf30bb89322e4911dd827495b88b4bdcac Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 22 Jan 2024 15:04:25 +0800 Subject: [PATCH 21/64] release 5.12.0 (#1394) Co-authored-by: Lo1nt --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index c4ce304bb..20e592155 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.11.1 + 5.12.0 ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 729329162..8e787532a 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.11.1 + 5.12.0 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 7e51652d2..9fb2b736b 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.11.1"; + public static final String VERSION = "5.12.0"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51101; + public static final int RPC_VERSION = 51200; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.11.1_20230911155412"; + public static final String BUILD_VERSION = "5.12.0_20240122111527"; } diff --git a/pom.xml b/pom.xml index 57e7f943e..3c8ab4cd2 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.11.1 + 5.12.0 1.33 true true From 357fdf04c96f639bc1bb827f4a5fe57bff568a83 Mon Sep 17 00:00:00 2001 From: evenliu Date: Thu, 22 Feb 2024 11:44:56 +0800 Subject: [PATCH 22/64] update rpc version to 5.13.0-SNAPSHOT (#1396) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 20e592155..3daa4e511 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.12.0 + 5.13.0-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 8e787532a..a97d8cc8f 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.12.0 + 5.13.0-SNAPSHOT 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 9fb2b736b..0860ef500 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.12.0"; + public static final String VERSION = "5.13.0"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51200; + public static final int RPC_VERSION = 51300; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.12.0_20240122111527"; + public static final String BUILD_VERSION = "5.13.0_20240222103719"; } diff --git a/pom.xml b/pom.xml index 3c8ab4cd2..ad0a95221 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.12.0 + 5.13.0-SNAPSHOT 1.33 true true From df2dcae4ed0dce12bfc210b5072e75f36b53f586 Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Thu, 29 Feb 2024 18:03:07 +0800 Subject: [PATCH 23/64] optimize UserThreadPoolManager (#1390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 呈铭 --- .../com/alipay/sofa/rpc/config/UserThreadPoolManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/UserThreadPoolManager.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/UserThreadPoolManager.java index 6f044f986..0f667ca0f 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/UserThreadPoolManager.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/UserThreadPoolManager.java @@ -81,9 +81,7 @@ public static UserThreadPool getUserThread(String service) { public static Set getUserThreadPoolSet() { Set userThreadPoolSet = new HashSet<>(); if (hasUserThread()) { - for (UserThreadPool userThreadPool : userThreadMap.values()) { - userThreadPoolSet.add(userThreadPool); - } + userThreadPoolSet.addAll(userThreadMap.values()); } return userThreadPoolSet; } From ac2a73ef018a1bdbd9da0075dd64f0c4ae309984 Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Tue, 12 Mar 2024 15:59:44 +0800 Subject: [PATCH 24/64] fix #1380, create NacosRegistryProviderObserver when init method is executed (#1401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix https://github.com/sofastack/sofa-rpc/issues/1380 * fix https://github.com/sofastack/sofa-rpc/issues/1380 --------- Co-authored-by: 呈铭 --- .../rpc/registry/nacos/NacosRegistry.java | 41 +++++++++++-------- .../rpc/registry/nacos/NacosRegistryTest.java | 37 +++++++++++++++-- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistry.java b/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistry.java index 7161a8702..98dec21bc 100644 --- a/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistry.java +++ b/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistry.java @@ -20,12 +20,12 @@ import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingFactory; import com.alibaba.nacos.api.naming.NamingService; -import com.alibaba.nacos.api.naming.listener.Event; import com.alibaba.nacos.api.naming.listener.EventListener; import com.alibaba.nacos.api.naming.listener.NamingEvent; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alipay.sofa.rpc.client.ProviderGroup; import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.annotation.VisibleForTesting; import com.alipay.sofa.rpc.common.utils.CommonUtils; import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.config.ConsumerConfig; @@ -146,6 +146,10 @@ public synchronized void init() { nacosConfig.putAll(parameters); } + if (providerObserver == null) { + providerObserver = new NacosRegistryProviderObserver(); + } + try { namingService = NamingFactory.createNamingService(nacosConfig); } catch (NacosException e) { @@ -272,26 +276,19 @@ public List subscribe(final ConsumerConfig config) { } try { - if (providerObserver == null) { - providerObserver = new NacosRegistryProviderObserver(); - } - ProviderInfoListener providerInfoListener = config.getProviderInfoListener(); providerObserver.addProviderListener(config, providerInfoListener); - EventListener eventListener = new EventListener() { - @Override - public void onEvent(Event event) { - if (event instanceof NamingEvent) { - NamingEvent namingEvent = (NamingEvent) event; - List instances = namingEvent.getInstances(); - // avoid npe - if (null == instances) { - instances = new ArrayList(); - } - instances.removeIf(i -> !i.isEnabled()); - providerObserver.updateProviders(config, instances); + EventListener eventListener = event -> { + if (event instanceof NamingEvent) { + NamingEvent namingEvent = (NamingEvent) event; + List instances = namingEvent.getInstances(); + // avoid npe + if (null == instances) { + instances = new ArrayList(); } + instances.removeIf(i -> !i.isEnabled()); + providerObserver.updateProviders(config, instances); } }; namingService.subscribe(serviceName, defaultCluster, eventListener); @@ -359,4 +356,14 @@ public void destroy() { public Properties getNacosConfig() { return nacosConfig; } + + /** + * UT only + * + * @return + */ + @VisibleForTesting + public NacosRegistryProviderObserver getProviderObserver() { + return providerObserver; + } } diff --git a/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryTest.java b/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryTest.java index 373af0eb6..dc6e7f114 100644 --- a/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryTest.java +++ b/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryTest.java @@ -18,6 +18,7 @@ import com.alipay.sofa.rpc.client.ProviderGroup; import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.struct.ConcurrentHashSet; import com.alipay.sofa.rpc.config.ApplicationConfig; import com.alipay.sofa.rpc.config.ConsumerConfig; import com.alipay.sofa.rpc.config.ProviderConfig; @@ -36,9 +37,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** @@ -66,8 +70,6 @@ public void setUp() { .setRegister(true); registry = (NacosRegistry) RegistryFactory.getRegistry(registryConfig); - registry.init(); - Assert.assertTrue(registry.start()); } /** @@ -77,7 +79,30 @@ public void setUp() { public void tearDown() { registry.destroy(); registry = null; - serverConfig.destroy(); + } + + @Test + public void testMuiltInit() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(10); + final CountDownLatch latch = new CountDownLatch(10); + Set sets = new ConcurrentHashSet<>(); + + for (int i = 0; i < 10; i++) { + executorService.submit(() -> { + try { + registry.init(); + NacosRegistryProviderObserver providerObserver = registry.getProviderObserver(); + sets.add(providerObserver); + } finally { + latch.countDown(); + } + }); + } + + latch.await(); + executorService.shutdown(); + + Assert.assertEquals(1, sets.size()); } /** @@ -87,6 +112,8 @@ public void tearDown() { */ @Test public void testProviderObserver() throws Exception { + registry.init(); + Assert.assertTrue(registry.start()); int timeoutPerSub = 2000; //wait nacos startup ok @@ -227,6 +254,7 @@ public void testProviderObserver() throws Exception { List consumerConfigList = new ArrayList<>(); consumerConfigList.add(consumer2); registry.batchUnSubscribe(consumerConfigList); + serverConfig.destroy(); } /** @@ -236,6 +264,8 @@ public void testProviderObserver() throws Exception { */ @Test public void testVirtualHostAndVirtualPort() throws Exception { + registry.init(); + Assert.assertTrue(registry.start()); //wait nacos startup ok TimeUnit.SECONDS.sleep(10); // 模拟的场景 client -> proxy:127.7.7.7:8888 -> netty:0.0.0.0:12200 @@ -297,6 +327,7 @@ public void testVirtualHostAndVirtualPort() throws Exception { virtualHost + ":" + virtualPort); Assert.assertEquals("The provider's host should be virtualHost", virtualHost, pri.getHost()); Assert.assertEquals("The provider's port should be virtualPort", virtualPort, pri.getPort()); + serverConfig.destroy(); } private static class MockProviderInfoListener implements ProviderInfoListener { From 6cf6f00cab935bdf957d712792d37ee32aff8191 Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Mon, 25 Mar 2024 10:13:23 +0800 Subject: [PATCH 25/64] support sofa registry kubernetes (#1395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 呈铭 --- all/pom.xml | 6 + bom/pom.xml | 15 + .../sofa/rpc/config/RegistryConfig.java | 30 ++ registry/pom.xml | 1 + registry/registry-kubernetes/pom.xml | 39 ++ .../kubernetes/KubernetesRegistry.java | 280 ++++++++++++++ .../kubernetes/KubernetesRegistryHelper.java | 101 +++++ .../KubernetesRegistryProviderWatcher.java | 77 ++++ .../constant/KubernetesClientConstants.java | 73 ++++ .../utils/KubernetesClientUtils.java | 28 ++ .../utils/KubernetesConfigUtils.java | 104 ++++++ .../com.alipay.sofa.rpc.registry.Registry | 1 + .../kubernetes/KubernetesRegistryTest.java | 345 ++++++++++++++++++ .../rpc/registry/kubernetes/TestService.java | 22 ++ .../rpc/registry/kubernetes/TestService2.java | 22 ++ .../registry/kubernetes/TestServiceImpl.java | 25 ++ .../registry/kubernetes/TestServiceImpl2.java | 25 ++ .../src/test/resources/log4j.xml | 16 + .../org.mockito.plugins.MockMaker | 1 + .../test/resources/sofa-rpc/rpc-config.json | 4 + 20 files changed, 1215 insertions(+) create mode 100644 registry/registry-kubernetes/pom.xml create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistry.java create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryHelper.java create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryProviderWatcher.java create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/constant/KubernetesClientConstants.java create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesClientUtils.java create mode 100644 registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesConfigUtils.java create mode 100644 registry/registry-kubernetes/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.registry.Registry create mode 100644 registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryTest.java create mode 100644 registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService.java create mode 100644 registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService2.java create mode 100644 registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl.java create mode 100644 registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl2.java create mode 100755 registry/registry-kubernetes/src/test/resources/log4j.xml create mode 100644 registry/registry-kubernetes/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker create mode 100644 registry/registry-kubernetes/src/test/resources/sofa-rpc/rpc-config.json diff --git a/all/pom.xml b/all/pom.xml index 3daa4e511..df0690331 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -244,6 +244,11 @@ sofa-rpc-registry-polaris ${project.version}
+ + com.alipay.sofa + sofa-rpc-registry-kubernetes + ${project.version} + com.alipay.sofa sofa-rpc-remoting-bolt @@ -545,6 +550,7 @@ com.alipay.sofa:sofa-rpc-registry-multicast com.alipay.sofa:sofa-rpc-registry-sofa com.alipay.sofa:sofa-rpc-registry-polaris + com.alipay.sofa:sofa-rpc-registry-kubernetes com.alipay.sofa:sofa-rpc-remoting-bolt com.alipay.sofa:sofa-rpc-remoting-http com.alipay.sofa:sofa-rpc-remoting-resteasy diff --git a/bom/pom.xml b/bom/pom.xml index a97d8cc8f..d43a6183d 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -60,6 +60,8 @@ true true + + 6.9.2
@@ -514,6 +516,19 @@ ${grpc.version} + + + io.fabric8 + kubernetes-client + ${fabric8_kubernetes_version} + + + io.fabric8 + kubernetes-server-mock + test + ${fabric8_kubernetes_version} + + org.apache.curator diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/RegistryConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/RegistryConfig.java index b11533728..674a89fa6 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/RegistryConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/RegistryConfig.java @@ -398,6 +398,36 @@ public String getParameter(String key) { return parameters == null ? null : parameters.get(key); } + /** + * Gets parameter or default. + * + * @param key the key + * @return the value + */ + public String getParameter(String key, String defaultValue) { + return getParameter(key) == null ? defaultValue : getParameter(key); + } + + /** + * Gets parameter or default. + * + * @param key the key + * @return the value + */ + public int getParameter(String key, int defaultValue) { + return getParameter(key) == null ? defaultValue : Integer.parseInt(parameters.get(key)); + } + + /** + * Gets parameter or default. + * + * @param key the key + * @return the value + */ + public boolean getParameter(String key, boolean defaultValue) { + return getParameter(key) == null ? defaultValue : Boolean.parseBoolean(parameters.get(key)); + } + @Override public String toString() { return "RegistryConfig{" + diff --git a/registry/pom.xml b/registry/pom.xml index e65411b8e..4dc28e046 100644 --- a/registry/pom.xml +++ b/registry/pom.xml @@ -22,6 +22,7 @@ registry-multicast registry-sofa registry-polaris + registry-kubernetes diff --git a/registry/registry-kubernetes/pom.xml b/registry/registry-kubernetes/pom.xml new file mode 100644 index 000000000..b3bb820ff --- /dev/null +++ b/registry/registry-kubernetes/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + + com.alipay.sofa + sofa-rpc-registry + ${revision} + + + sofa-rpc-registry-kubernetes + + + + com.alipay.sofa + sofa-rpc-log + + + com.alipay.sofa + sofa-rpc-api + + + com.alipay.sofa + sofa-rpc-codec-api + + + io.fabric8 + kubernetes-client + + + io.fabric8 + kubernetes-server-mock + test + + + + diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistry.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistry.java new file mode 100644 index 000000000..7f4e616a4 --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistry.java @@ -0,0 +1,280 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes; + +import com.alipay.sofa.rpc.client.ProviderGroup; +import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.annotation.VisibleForTesting; +import com.alipay.sofa.rpc.common.utils.CommonUtils; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.RegistryConfig; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.listener.ProviderInfoListener; +import com.alipay.sofa.rpc.log.LogCodes; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.registry.Registry; +import com.alipay.sofa.rpc.registry.kubernetes.utils.KubernetesClientUtils; +import com.alipay.sofa.rpc.registry.kubernetes.utils.KubernetesConfigUtils; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.PodList; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable; +import io.fabric8.kubernetes.client.dsl.PodResource; +import io.fabric8.kubernetes.client.informers.ResourceEventHandler; +import io.fabric8.kubernetes.client.informers.SharedIndexInformer; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +@Extension("kubernetes") +public class KubernetesRegistry extends Registry { + + /** + * slf4j Logger for this class + */ + private final static Logger LOGGER = LoggerFactory.getLogger(KubernetesRegistry.class); + + private KubernetesClient kubernetesClient; + + private String currentHostname; + + private String namespace; + + private KubernetesRegistryProviderWatcher kubernetesRegistryProviderWatcher; + + private final ConcurrentMap> consumerListeners = new ConcurrentHashMap<>(64); + + /** + * Instantiates a new kubernetes registry. + * + * @param registryConfig + */ + public KubernetesRegistry(RegistryConfig registryConfig) { + super(registryConfig); + } + + @Override + public synchronized void init() { + // init kubernetes config + Config config = KubernetesConfigUtils.buildKubernetesConfig(registryConfig); + // init kubernetes client + if (kubernetesClient == null) { + this.kubernetesClient = KubernetesClientUtils.buildKubernetesClient(config); + } + // init Watcher + if (kubernetesRegistryProviderWatcher == null) { + kubernetesRegistryProviderWatcher = new KubernetesRegistryProviderWatcher(); + } + this.currentHostname = System.getenv("HOSTNAME"); + this.namespace = config.getNamespace(); + } + + @Override + public boolean start() { + return true; + } + + @Override + public void register(ProviderConfig config) { + String appName = config.getAppName(); + if (!registryConfig.isRegister()) { + if (LOGGER.isInfoEnabled(appName)) { + LOGGER.infoWithApp(appName, LogCodes.getLog(LogCodes.INFO_REGISTRY_IGNORE)); + } + return; + } + + if (config.isRegister()) { + PodResource podResource = kubernetesClient.pods() + .inNamespace(namespace) + .withName(currentHostname); + + List serverConfigs = config.getServer(); + + if (CommonUtils.isNotEmpty(serverConfigs)) { + for (ServerConfig serverConfig : serverConfigs) { + String dataId = KubernetesRegistryHelper.buildDataId(config, serverConfig.getProtocol()); + // 对外提供服务的URL + String url = KubernetesRegistryHelper.convertToUrl(podResource.get(), serverConfig, config); + + podResource.edit(pod -> new PodBuilder(pod).editOrNewMetadata() + // 将ProviderConfig存在Annotations上 + .addToAnnotations(dataId, url) + // 为了过滤pod、其实value是用不到的 + .addToLabels(dataId, "") + .endMetadata().build()); + } + } + } + } + + @Override + public void unRegister(ProviderConfig config) { + String appName = config.getAppName(); + if (!registryConfig.isRegister()) { + if (LOGGER.isInfoEnabled(appName)) { + LOGGER.infoWithApp(appName, LogCodes.getLog(LogCodes.INFO_REGISTRY_IGNORE)); + } + return; + } + + if (config.isRegister()) { + PodResource podResource = kubernetesClient.pods() + .inNamespace(namespace) + .withName(currentHostname); + + List serverConfigs = config.getServer(); + if (CommonUtils.isNotEmpty(serverConfigs)) { + for (ServerConfig serverConfig : serverConfigs) { + String dataId = KubernetesRegistryHelper.buildDataId(config, serverConfig.getProtocol()); + + podResource.edit(pod -> new PodBuilder(pod).editOrNewMetadata() + .removeFromAnnotations(dataId) + .removeFromLabels(dataId) + .endMetadata() + .build()); + } + } + } + } + + @Override + public void batchUnRegister(List configs) { + // one by one + for (ProviderConfig config : configs) { + try { + this.unRegister(config); + } catch (Exception e) { + LOGGER.errorWithApp(config.getAppName(), "Batch unregister error", e); + } + } + } + + @Override + public List subscribe(ConsumerConfig config) { + String appName = config.getAppName(); + if (!registryConfig.isSubscribe()) { + // registry ignored + if (LOGGER.isInfoEnabled(appName)) { + LOGGER.infoWithApp(appName, LogCodes.getLog(LogCodes.INFO_REGISTRY_IGNORE)); + } + return null; + } + + if (config.isSubscribe()) { + + ProviderInfoListener providerInfoListener = config.getProviderInfoListener(); + kubernetesRegistryProviderWatcher.addProviderListener(config, providerInfoListener); + + String dataId = KubernetesRegistryHelper.buildDataId(config, config.getProtocol()); + FilterWatchListDeletable podPodListPodResourceFilterWatchListDeletable = + kubernetesClient.pods() + .inNamespace(namespace) + .withLabel(dataId); + + SharedIndexInformer inform = podPodListPodResourceFilterWatchListDeletable.inform(new ResourceEventHandler() { + @Override + public void onAdd(Pod pod) { + kubernetesRegistryProviderWatcher.updateProviders(config, getPods()); + } + + @Override + public void onUpdate(Pod pod, Pod t1) { + kubernetesRegistryProviderWatcher.updateProviders(config, getPods()); + } + + @Override + public void onDelete(Pod pod, boolean b) { + kubernetesRegistryProviderWatcher.updateProviders(config, getPods()); + } + }); + + consumerListeners.put(config, inform); + + inform.start(); + + List pods = podPodListPodResourceFilterWatchListDeletable.list().getItems(); + List providerInfos = KubernetesRegistryHelper.convertPodsToProviders(pods, config); + return Collections.singletonList(new ProviderGroup().addAll(providerInfos)); + } + + return null; + } + + @Override + public void unSubscribe(ConsumerConfig config) { + if (config.isSubscribe()) { + SharedIndexInformer informer = consumerListeners.remove(config); + if (null != informer) { + informer.stop(); + } + } + + kubernetesRegistryProviderWatcher.removeProviderListener(config); + } + + @Override + public void batchUnSubscribe(List configs) { + // one by one + for (ConsumerConfig config : configs) { + try { + this.unSubscribe(config); + } catch (Exception e) { + LOGGER.errorWithApp(config.getAppName(), "Batch unSubscribe error", e); + } + } + } + + @Override + public void destroy() { + // unRegister consumer + consumerListeners.forEach((k, v) -> unSubscribe(k)); + + // close kubernetes client + kubernetesClient.close(); + } + + private List getPods() { + return kubernetesClient.pods() + .inNamespace(namespace) + .list() + .getItems(); + } + + /** + * UT used only + */ + @VisibleForTesting + public void setCurrentHostname(String currentHostname) { + this.currentHostname = currentHostname; + } + + /** + * UT used only + */ + @VisibleForTesting + public ConcurrentMap> getConsumerListeners() { + return consumerListeners; + } +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryHelper.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryHelper.java new file mode 100644 index 000000000..ca61fe851 --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryHelper.java @@ -0,0 +1,101 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes; + +import com.alipay.sofa.rpc.client.ProviderHelper; +import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.common.utils.CommonUtils; +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.config.AbstractInterfaceConfig; +import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.registry.utils.RegistryUtils; +import io.fabric8.kubernetes.api.model.Pod; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class KubernetesRegistryHelper extends RegistryUtils { + + private final static Logger LOGGER = LoggerFactory.getLogger(KubernetesRegistryHelper.class); + + public static List convertPodsToProviders(List pods, ConsumerConfig config) { + List providerInfos = new ArrayList<>(); + if (CommonUtils.isEmpty(pods) || null == config) { + return providerInfos; + } + + for (Pod pod : pods) { + ProviderInfo providerInfo = getProviderInfo(pod, config); + if (null == providerInfo) { + continue; + } + providerInfos.add(providerInfo); + } + + return providerInfos; + } + + public static String convertToUrl(Pod pod, ServerConfig serverConfig, ProviderConfig providerConfig) { + String uri = ""; + String protocol = serverConfig.getProtocol(); + if (StringUtils.isNotEmpty(protocol)) { + uri = protocol + "://"; + } + uri += pod.getStatus().getPodIP() + ":" + serverConfig.getPort(); + + Map metaData = RegistryUtils.convertProviderToMap(providerConfig, serverConfig); + + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : metaData.entrySet()) { + sb.append("&").append(entry.getKey()).append("=").append(entry.getValue()); + } + if (sb.length() > 0) { + uri += sb.replace(0, 1, "?").toString(); + } + return uri; + } + + private static ProviderInfo getProviderInfo(Pod pod, ConsumerConfig config) { + try { + String dataId = buildDataId(config, config.getProtocol()); + String providerUrlString = pod.getMetadata().getAnnotations().get(dataId); + + if (StringUtils.isBlank(providerUrlString)) { + return null; + } + return ProviderHelper.toProviderInfo(providerUrlString); + } catch (Exception e) { + LOGGER.info("get provider config error with pod"); + return null; + } + } + + public static String buildDataId(AbstractInterfaceConfig config, String protocol) { + if (RpcConstants.PROTOCOL_TYPE_BOLT.equals(protocol) || RpcConstants.PROTOCOL_TYPE_TR.equals(protocol)) { + return ConfigUniqueNameGenerator.getUniqueName(config) + "@DEFAULT"; + } else { + return ConfigUniqueNameGenerator.getUniqueName(config) + "@" + protocol; + } + } +} diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryProviderWatcher.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryProviderWatcher.java new file mode 100644 index 000000000..8c026427b --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryProviderWatcher.java @@ -0,0 +1,77 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes; + +import com.alipay.sofa.rpc.client.ProviderGroup; +import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.utils.CommonUtils; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.listener.ProviderInfoListener; +import com.alipay.sofa.rpc.registry.utils.RegistryUtils; +import io.fabric8.kubernetes.api.model.Pod; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class KubernetesRegistryProviderWatcher { + + /** + * The Provider add listener map. + */ + private final ConcurrentMap> providerListenerMap = new ConcurrentHashMap<>(); + + /** + * Add provider listener. + * + * @param consumerConfig the consumer config + * @param listener the listener + */ + public void addProviderListener(ConsumerConfig consumerConfig, ProviderInfoListener listener) { + if (listener != null) { + RegistryUtils.initOrAddList(providerListenerMap, consumerConfig, listener); + } + } + + /** + * Remove provider listener. + * + * @param consumerConfig the consumer config + */ + public void removeProviderListener(ConsumerConfig consumerConfig) { + providerListenerMap.remove(consumerConfig); + } + + /** + * Update providers. + * + * @param config the config + * @param podList the pod list + */ + public void updateProviders(ConsumerConfig config, List podList) { + List providerInfoListeners = providerListenerMap.get(config); + if (CommonUtils.isNotEmpty(providerInfoListeners)) { + List providerInfos = KubernetesRegistryHelper.convertPodsToProviders(podList, config); + + for (ProviderInfoListener providerInfoListener : providerInfoListeners) { + providerInfoListener.updateAllProviders(Collections.singletonList(new ProviderGroup().addAll(providerInfos))); + } + } + } + +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/constant/KubernetesClientConstants.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/constant/KubernetesClientConstants.java new file mode 100644 index 000000000..4bd508296 --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/constant/KubernetesClientConstants.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 com.alipay.sofa.rpc.registry.kubernetes.constant; + +public class KubernetesClientConstants { + + public static final String DEFAULT_MASTER_URL = "https://kubernetes.default.svc"; + + public static final String TRUST_CERTS = "trustCerts"; + + public static final String USE_HTTPS = "useHttps"; + + public static final String HTTP2_DISABLE = "http2Disable"; + + public static final String NAMESPACE = "namespace"; + + public static final String API_VERSION = "apiVersion"; + + public static final String CA_CERT_FILE = "caCertFile"; + + public static final String CA_CERT_DATA = "caCertData"; + + public static final String CLIENT_CERT_FILE = "clientCertFile"; + + public static final String CLIENT_CERT_DATA = "clientCertData"; + + public static final String CLIENT_KEY_FILE = "clientKeyFile"; + + public static final String CLIENT_KEY_DATA = "clientKeyData"; + + public static final String CLIENT_KEY_ALGO = "clientKeyAlgo"; + + public static final String CLIENT_KEY_PASSPHRASE = "clientKeyPassphrase"; + + public static final String OAUTH_TOKEN = "oauthToken"; + + public static final String USERNAME = "username"; + + public static final String PASSWORD = "password"; + + public static final String WATCH_RECONNECT_INTERVAL = "watchReconnectInterval"; + + public static final String WATCH_RECONNECT_LIMIT = "watchReconnectLimit"; + + public static final String CONNECTION_TIMEOUT = "connectionTimeout"; + + public static final String REQUEST_TIMEOUT = "requestTimeout"; + + public static final String LOGGING_INTERVAL = "loggingInterval"; + + public static final String HTTP_PROXY = "httpProxy"; + + public static final String HTTPS_PROXY = "httpsProxy"; + + public static final String PROXY_USERNAME = "proxyUsername"; + + public static final String PROXY_PASSWORD = "proxyPassword"; + +} diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesClientUtils.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesClientUtils.java new file mode 100644 index 000000000..274d40a99 --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesClientUtils.java @@ -0,0 +1,28 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes.utils; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; + +public class KubernetesClientUtils { + + public static KubernetesClient buildKubernetesClient(Config config) { + return new KubernetesClientBuilder().withConfig(config).build(); + } +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesConfigUtils.java b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesConfigUtils.java new file mode 100644 index 000000000..f7aea188f --- /dev/null +++ b/registry/registry-kubernetes/src/main/java/com/alipay/sofa/rpc/registry/kubernetes/utils/KubernetesConfigUtils.java @@ -0,0 +1,104 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes.utils; + +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.config.RegistryConfig; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; + +import java.util.Base64; + +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.API_VERSION; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CA_CERT_DATA; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CA_CERT_FILE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_CERT_DATA; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_CERT_FILE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_KEY_ALGO; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_KEY_DATA; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_KEY_FILE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CLIENT_KEY_PASSPHRASE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.CONNECTION_TIMEOUT; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.DEFAULT_MASTER_URL; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.HTTP2_DISABLE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.HTTPS_PROXY; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.HTTP_PROXY; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.LOGGING_INTERVAL; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.NAMESPACE; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.OAUTH_TOKEN; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.PASSWORD; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.PROXY_PASSWORD; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.PROXY_USERNAME; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.REQUEST_TIMEOUT; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.TRUST_CERTS; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.USERNAME; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.USE_HTTPS; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.WATCH_RECONNECT_INTERVAL; +import static com.alipay.sofa.rpc.registry.kubernetes.constant.KubernetesClientConstants.WATCH_RECONNECT_LIMIT; + +public class KubernetesConfigUtils { + + public static Config buildKubernetesConfig(RegistryConfig registryConfig) { + + // Init default config + Config base = Config.autoConfigure(null); + + return new ConfigBuilder(base) + .withMasterUrl(buildMasterUrl(registryConfig)) + .withApiVersion(registryConfig.getParameter(API_VERSION, base.getApiVersion())) + .withNamespace(registryConfig.getParameter(NAMESPACE, base.getNamespace())) + .withUsername(registryConfig.getParameter(USERNAME, base.getUsername())) + .withPassword(registryConfig.getParameter(PASSWORD, base.getPassword())) + .withOauthToken(registryConfig.getParameter(OAUTH_TOKEN, base.getOauthToken())) + .withCaCertFile(registryConfig.getParameter(CA_CERT_FILE, base.getCaCertFile())) + .withCaCertData(registryConfig.getParameter(CA_CERT_DATA, decodeBase64(base.getCaCertData()))) + .withClientKeyFile(registryConfig.getParameter(CLIENT_KEY_FILE, base.getClientKeyFile())) + .withClientKeyData(registryConfig.getParameter(CLIENT_KEY_DATA, decodeBase64(base.getClientKeyData()))) + .withClientCertFile(registryConfig.getParameter(CLIENT_CERT_FILE, base.getClientCertFile())) + .withClientCertData(registryConfig.getParameter(CLIENT_CERT_DATA, decodeBase64(base.getClientCertData()))) + .withClientKeyAlgo(registryConfig.getParameter(CLIENT_KEY_ALGO, base.getClientKeyAlgo())) + .withClientKeyPassphrase(registryConfig.getParameter(CLIENT_KEY_PASSPHRASE, base.getClientKeyPassphrase())) + .withConnectionTimeout(registryConfig.getParameter(CONNECTION_TIMEOUT, base.getConnectionTimeout())) + .withRequestTimeout(registryConfig.getParameter(REQUEST_TIMEOUT, base.getRequestTimeout())) + .withWatchReconnectInterval( + registryConfig.getParameter(WATCH_RECONNECT_INTERVAL, base.getWatchReconnectInterval())) + .withWatchReconnectLimit(registryConfig.getParameter(WATCH_RECONNECT_LIMIT, base.getWatchReconnectLimit())) + .withLoggingInterval(registryConfig.getParameter(LOGGING_INTERVAL, base.getLoggingInterval())) + .withTrustCerts(registryConfig.getParameter(TRUST_CERTS, base.isTrustCerts())) + .withHttp2Disable(registryConfig.getParameter(HTTP2_DISABLE, base.isHttp2Disable())) + .withHttpProxy(registryConfig.getParameter(HTTP_PROXY, base.getHttpProxy())) + .withHttpsProxy(registryConfig.getParameter(HTTPS_PROXY, base.getHttpsProxy())) + .withProxyUsername(registryConfig.getParameter(PROXY_USERNAME, base.getProxyUsername())) + .withProxyPassword(registryConfig.getParameter(PROXY_PASSWORD, base.getProxyPassword())) + .build(); + } + + private static String buildMasterUrl(RegistryConfig registryConfig) { + String address = registryConfig.getAddress(); + if (StringUtils.isBlank(address)) { + return DEFAULT_MASTER_URL; + } + if (address.startsWith("http")) { + return address; + } + return registryConfig.getParameter(USE_HTTPS, true) ? "https://" + address : "http://" + address; + } + + private static String decodeBase64(String str) { + return StringUtils.isNotEmpty(str) ? new String(Base64.getDecoder().decode(str)) : null; + } +} diff --git a/registry/registry-kubernetes/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.registry.Registry b/registry/registry-kubernetes/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.registry.Registry new file mode 100644 index 000000000..3bf1f8e63 --- /dev/null +++ b/registry/registry-kubernetes/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.registry.Registry @@ -0,0 +1 @@ +kubernetes=com.alipay.sofa.rpc.registry.kubernetes.KubernetesRegistry \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryTest.java b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryTest.java new file mode 100644 index 000000000..7f543df82 --- /dev/null +++ b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/KubernetesRegistryTest.java @@ -0,0 +1,345 @@ +/* + * 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 com.alipay.sofa.rpc.registry.kubernetes; + +import com.alipay.sofa.rpc.client.ProviderGroup; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.config.ApplicationConfig; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.RegistryConfig; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.context.RpcInternalContext; +import com.alipay.sofa.rpc.context.RpcInvokeContext; +import com.alipay.sofa.rpc.context.RpcRunningState; +import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import com.alipay.sofa.rpc.listener.ProviderInfoListener; +import io.fabric8.kubernetes.api.model.Endpoints; +import io.fabric8.kubernetes.api.model.EndpointsBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.NamespacedKubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static com.alipay.sofa.rpc.registry.kubernetes.KubernetesRegistryHelper.buildDataId; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class KubernetesRegistryTest { + + private static final String NAMESPACE = "TestNameSpace"; + private static final String POD_NAME = "TestPodName"; + private static final String APP_NAME = "TestAppName"; + private static final String SERVICE_NAME = "TestService"; + + public KubernetesServer mockServer; + + private NamespacedKubernetesClient mockClient; + + private static KubernetesRegistry kubernetesRegistry; + + private static RegistryConfig registryConfig; + + private static ConsumerConfig consumer; + + /** + * Ad before class. + */ + @BeforeClass + public static void adBeforeClass() { + RpcRunningState.setUnitTestMode(true); + } + + /** + * Ad after class. + */ + @AfterClass + public static void adAfterClass() { + RpcRuntimeContext.destroy(); + RpcInternalContext.removeContext(); + RpcInvokeContext.removeContext(); + } + + @Before + public void setup() { + mockServer = new KubernetesServer(false, true); + mockServer.before(); + mockClient = mockServer.getClient().inNamespace(NAMESPACE); + + registryConfig = new RegistryConfig(); + registryConfig.setProtocol("kubernetes"); + registryConfig.setAddress(mockClient.getConfiguration().getMasterUrl()); + // registryConfig.setParameter("trustCerts", "true"); + registryConfig.setParameter("namespace", NAMESPACE); + registryConfig.setParameter("useHttps", "false"); + registryConfig.setParameter("http2Disable", "true"); + + kubernetesRegistry = new KubernetesRegistry(registryConfig); + kubernetesRegistry.init(); + kubernetesRegistry.setCurrentHostname(POD_NAME); + + System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false"); + System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false"); + + Pod pod = new PodBuilder() + .withNewMetadata() + .withName(POD_NAME) + .endMetadata() + .withNewStatus() + .withPodIP("192.168.1.100") + .endStatus() + .build(); + + Service service = new ServiceBuilder() + .withNewMetadata() + .withName(SERVICE_NAME) + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + + Endpoints endPoints = new EndpointsBuilder() + .withNewMetadata() + .withName(SERVICE_NAME) + .endMetadata() + .addNewSubset() + .addNewAddress() + .withIp("ip1") + .withNewTargetRef() + .withUid("uid1") + .withName(POD_NAME) + .endTargetRef() + .endAddress() + .addNewPort("Test", "Test", 12345, "TCP") + .endSubset() + .build(); + + mockClient.pods().inNamespace(NAMESPACE).create(pod); + mockClient.services().inNamespace(NAMESPACE).create(service); + mockClient.endpoints().inNamespace(NAMESPACE).create(endPoints); + + Assert.assertTrue(kubernetesRegistry.start()); + } + + @After + public void cleanup() { + kubernetesRegistry.destroy(); + mockClient.close(); + mockServer.after(); + } + + @Test + public void testAll() throws InterruptedException { + ApplicationConfig applicationConfig = new ApplicationConfig() + .setAppName(APP_NAME); + + ServerConfig serverConfig1 = new ServerConfig() + .setProtocol("bolt") + .setPort(12200) + .setDaemon(false); + + ProviderConfig providerConfig1 = new ProviderConfig() + .setApplication(applicationConfig) + .setInterfaceId(TestService.class.getName()) + .setRegistry(registryConfig) + .setRegister(true) + // .setUniqueId("standalone") + .setRef(new TestServiceImpl()) + .setDelay(20) + .setServer(serverConfig1); + + // 注册第一个providerConfig1 + kubernetesRegistry.register(providerConfig1); + + ServerConfig serverConfig2 = new ServerConfig() + .setProtocol("h2c") + .setPort(12202) + .setDaemon(false); + + ProviderConfig providerConfig2 = new ProviderConfig() + .setApplication(applicationConfig) + .setInterfaceId(TestService2.class.getName()) + .setRegistry(registryConfig) + .setRegister(true) + // .setUniqueId("standalone") + .setRef(new TestServiceImpl2()) + .setDelay(20) + .setServer(serverConfig2); + + // 注册第二个providerConfig2 + kubernetesRegistry.register(providerConfig2); + + List items = mockClient.pods().inNamespace(NAMESPACE).list().getItems(); + + Assert.assertEquals(1, items.size()); + Pod pod = items.get(0); + String annotationBolt = pod.getMetadata().getAnnotations().get(buildDataId(providerConfig1, "bolt")); + Assert.assertNotNull(annotationBolt); + String annotationH2c = pod.getMetadata().getAnnotations().get(buildDataId(providerConfig2, "h2c")); + Assert.assertNotNull(annotationH2c); + + // 订阅 + consumer = new ConsumerConfig(); + consumer.setInterfaceId("com.alipay.sofa.rpc.registry.kubernetes.TestService") + .setApplication(applicationConfig) + .setProxy("javassist") + .setSubscribe(true) + .setSerialization("java") + .setInvokeType("sync") + .setTimeout(4444); + + CountDownLatch latch = new CountDownLatch(1); + MockProviderInfoListener providerInfoListener = new MockProviderInfoListener(); + providerInfoListener.setCountDownLatch(latch); + consumer.setProviderInfoListener(providerInfoListener); + List all = kubernetesRegistry.subscribe(consumer); + providerInfoListener.updateAllProviders(all); + latch.await(5000, TimeUnit.MILLISECONDS); + Map ps = providerInfoListener.getData(); + + Assert.assertEquals(1, kubernetesRegistry.getConsumerListeners().size()); + Assert.assertTrue(ps.size() > 0); + Assert.assertEquals(1, ps.size()); + Assert.assertNotNull(ps.get(RpcConstants.ADDRESS_DEFAULT_GROUP)); + Assert.assertTrue(ps.get(RpcConstants.ADDRESS_DEFAULT_GROUP).size() > 0); + + // 一次发2个端口的再次注册 + latch = new CountDownLatch(2); + providerInfoListener.setCountDownLatch(latch); + ServerConfig serverConfig = new ServerConfig() + .setProtocol("bolt") + .setHost("0.0.0.0") + .setDaemon(false) + .setPort(12201); + providerConfig1.getServer().add(serverConfig); + kubernetesRegistry.register(providerConfig1); + latch.await(5000 * 2, TimeUnit.MILLISECONDS); + Assert.assertTrue(ps.size() > 0); + Assert.assertNotNull(ps.get(RpcConstants.ADDRESS_DEFAULT_GROUP)); + Assert.assertEquals(1, ps.get(RpcConstants.ADDRESS_DEFAULT_GROUP).size()); + + // 反订阅 + kubernetesRegistry.unSubscribe(consumer); + Assert.assertEquals(0, kubernetesRegistry.getConsumerListeners().size()); + + // 反注册providerConfig1 + kubernetesRegistry.unRegister(providerConfig1); + // 反注册providerConfig2 + kubernetesRegistry.unRegister(providerConfig2); + + List unRegisterItems = mockClient.pods().inNamespace(NAMESPACE).list().getItems(); + Assert.assertEquals(0, unRegisterItems.get(0).getMetadata().getAnnotations().size()); + } + + private static class MockProviderInfoListener implements ProviderInfoListener { + + Map providerGroupMap = new HashMap<>(); + + private CountDownLatch countDownLatch; + + public void setCountDownLatch(CountDownLatch countDownLatch) { + this.countDownLatch = countDownLatch; + } + + @Override + public void addProvider(ProviderGroup providerGroup) { + + } + + @Override + public void removeProvider(ProviderGroup providerGroup) { + + } + + @Override + public void updateProviders(ProviderGroup providerGroup) { + + providerGroupMap.put(providerGroup.getName(), providerGroup); + if (countDownLatch != null) { + countDownLatch.countDown(); + countDownLatch = null; + } + } + + @Override + public void updateAllProviders(List providerGroups) { + providerGroupMap.clear(); + + if (providerGroups == null || providerGroups.size() == 0) { + } else { + for (ProviderGroup p : providerGroups) { + providerGroupMap.put(p.getName(), p); + } + + } + } + + public Map getData() { + return providerGroupMap; + } + } + + @Test + public void testUpdatePodAnnotations() { + + // 创建一个新的 Pod + String podName = "test-pod"; + String namespace = "test-namespace"; + Pod pod = new PodBuilder() + .withNewMetadata() + .withName(podName) + .withNamespace(namespace) + .endMetadata() + .build(); + + // 在模拟环境中创建 Pod + pod = mockClient.pods().inNamespace(namespace).create(pod); + assertNotNull(pod); + + // 准备要更新的 annotations + Map annotations = new HashMap<>(); + annotations.put("example.com/annotation", "value"); + + // 更新 Pod 的 annotations + pod = new PodBuilder(pod) + .editMetadata() + .addToAnnotations(annotations) + .endMetadata() + .build(); + + // 在模拟环境中更新 Pod + pod = mockClient.pods().inNamespace(namespace).withName(podName).replace(pod); + + // 获取并验证 annotations 是否已更新 + assertEquals("value", pod.getMetadata().getAnnotations().get("example.com/annotation")); + } +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService.java b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService.java new file mode 100644 index 000000000..8cb791154 --- /dev/null +++ b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService.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 com.alipay.sofa.rpc.registry.kubernetes; + +public interface TestService { + + String sayHello(String str); +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService2.java b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService2.java new file mode 100644 index 000000000..30d7392e6 --- /dev/null +++ b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestService2.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 com.alipay.sofa.rpc.registry.kubernetes; + +public interface TestService2 { + + String sayHello(String str); +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl.java b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl.java new file mode 100644 index 000000000..25b7cc7c3 --- /dev/null +++ b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl.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 com.alipay.sofa.rpc.registry.kubernetes; + +public class TestServiceImpl implements TestService { + + @Override + public String sayHello(String str) { + return str; + } +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl2.java b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl2.java new file mode 100644 index 000000000..bc6c3aa1b --- /dev/null +++ b/registry/registry-kubernetes/src/test/java/com/alipay/sofa/rpc/registry/kubernetes/TestServiceImpl2.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 com.alipay.sofa.rpc.registry.kubernetes; + +public class TestServiceImpl2 implements TestService2 { + + @Override + public String sayHello(String str) { + return str; + } +} \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/resources/log4j.xml b/registry/registry-kubernetes/src/test/resources/log4j.xml new file mode 100755 index 000000000..e95634f16 --- /dev/null +++ b/registry/registry-kubernetes/src/test/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/registry/registry-kubernetes/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..ca6ee9cea --- /dev/null +++ b/registry/registry-kubernetes/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/registry/registry-kubernetes/src/test/resources/sofa-rpc/rpc-config.json b/registry/registry-kubernetes/src/test/resources/sofa-rpc/rpc-config.json new file mode 100644 index 000000000..a555027fe --- /dev/null +++ b/registry/registry-kubernetes/src/test/resources/sofa-rpc/rpc-config.json @@ -0,0 +1,4 @@ +{ + "rpc.config.order": 999, // 加载顺序,越大越后加载 + "logger.impl" : "com.alipay.sofa.rpc.log.SLF4JLoggerImpl" +} \ No newline at end of file From 70f16f3c550aeb40e9c8ac8e63870ad9c8c4992b Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 25 Mar 2024 15:43:08 +0800 Subject: [PATCH 26/64] fix lost interface name and method name in tracer when no such method case. (#1397) Co-authored-by: liujianjun.ljj --- .../bootstrap/DefaultClientProxyInvoker.java | 1 + .../sofatracer/ProviderTracerFilter.java | 40 ++------ .../rpc/tracer/sofatracer/RpcSofaTracer.java | 18 +++- .../rpc/event/SofaTracerSubscriberTest.java | 93 +++++++++++++++++++ 4 files changed, 118 insertions(+), 34 deletions(-) create mode 100644 tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java diff --git a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultClientProxyInvoker.java b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultClientProxyInvoker.java index afcfcc7af..0aadda9c9 100644 --- a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultClientProxyInvoker.java +++ b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultClientProxyInvoker.java @@ -133,6 +133,7 @@ protected void decorateRequest(SofaRequest request) { // 额外属性通过HEAD传递给服务端 request.addRequestProp(RemotingConstants.HEAD_APP_NAME, consumerConfig.getAppName()); request.addRequestProp(RemotingConstants.HEAD_PROTOCOL, consumerConfig.getProtocol()); + request.addRequestProp(RemotingConstants.HEAD_INVOKE_TYPE, request.getInvokeType()); customRequest(request, internalContext); diff --git a/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/filter/sofatracer/ProviderTracerFilter.java b/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/filter/sofatracer/ProviderTracerFilter.java index 3e01989ba..9bac54c5d 100644 --- a/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/filter/sofatracer/ProviderTracerFilter.java +++ b/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/filter/sofatracer/ProviderTracerFilter.java @@ -19,9 +19,7 @@ import com.alipay.common.tracer.core.context.trace.SofaTraceContext; import com.alipay.common.tracer.core.holder.SofaTraceContextHolder; import com.alipay.common.tracer.core.span.SofaTracerSpan; -import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.config.ProviderConfig; -import com.alipay.sofa.rpc.context.RpcInternalContext; import com.alipay.sofa.rpc.core.exception.SofaRpcException; import com.alipay.sofa.rpc.core.request.SofaRequest; import com.alipay.sofa.rpc.core.response.SofaResponse; @@ -32,10 +30,6 @@ import com.alipay.sofa.rpc.module.SofaTracerModule; import com.alipay.sofa.rpc.tracer.sofatracer.log.tags.RpcSpanTags; -import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_APP_NAME; -import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_INVOKE_TYPE; -import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_PROTOCOL; - /** * @author zhanggeng */ @@ -50,34 +44,14 @@ public boolean needToLoad(FilterInvoker invoker) { @Override public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException { - SofaTracerSpan serverSpan = null; - try { - SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); - serverSpan = sofaTraceContext.getCurrentSpan(); - if (serverSpan != null) { - RpcInternalContext context = RpcInternalContext.getContext(); - serverSpan.setTag(RpcSpanTags.SERVICE, request.getTargetServiceUniqueName()); - serverSpan.setTag(RpcSpanTags.METHOD, request.getMethodName()); - serverSpan.setTag(RpcSpanTags.REMOTE_IP, context.getRemoteHostName()); // 客户端地址 - - // 从请求里获取ConsumerTracerFilter额外传递的信息 - serverSpan.setTag(RpcSpanTags.REMOTE_APP, (String) request.getRequestProp(HEAD_APP_NAME)); - serverSpan.setTag(RpcSpanTags.PROTOCOL, (String) request.getRequestProp(HEAD_PROTOCOL)); - serverSpan.setTag(RpcSpanTags.INVOKE_TYPE, (String) request.getRequestProp(HEAD_INVOKE_TYPE)); - - ProviderConfig providerConfig = (ProviderConfig) invoker.getConfig(); - serverSpan.setTag(RpcSpanTags.LOCAL_APP, providerConfig.getAppName()); - - serverSpan.setTag(RpcSpanTags.SERVER_THREAD_POOL_WAIT_TIME, - (Number) context.getAttachment(RpcConstants.INTERNAL_KEY_PROCESS_WAIT_TIME)); - } - return invoker.invoke(request); - } finally { - if (serverSpan != null) { - serverSpan.setTag(RpcSpanTags.SERVER_BIZ_TIME, - (Number) RpcInternalContext.getContext().getAttachment(RpcConstants.INTERNAL_KEY_IMPL_ELAPSE)); - } + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + SofaTracerSpan serverSpan = sofaTraceContext.getCurrentSpan(); + if (serverSpan != null) { + ProviderConfig providerConfig = (ProviderConfig) invoker.getConfig(); + serverSpan.setTag(RpcSpanTags.LOCAL_APP, providerConfig.getAppName()); } + return invoker.invoke(request); + } } diff --git a/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/RpcSofaTracer.java b/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/RpcSofaTracer.java index 9be88bae8..ac3a24d54 100644 --- a/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/RpcSofaTracer.java +++ b/tracer/tracer-opentracing/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/RpcSofaTracer.java @@ -61,6 +61,10 @@ import java.util.TreeMap; import java.util.concurrent.TimeUnit; +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_APP_NAME; +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_INVOKE_TYPE; +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_PROTOCOL; + /** * SofaTracer * @@ -490,11 +494,19 @@ public void serverReceived(SofaRequest request) { // Record server receive event serverSpan.log(LogData.SERVER_RECV_EVENT_VALUE); + // Retrieve logging context information from the request + RpcInternalContext context = RpcInternalContext.getContext(); + serverSpan.setTag(RpcSpanTags.LOCAL_APP, request.getTargetAppName()); + serverSpan.setTag(RpcSpanTags.SERVICE, request.getTargetServiceUniqueName()); + serverSpan.setTag(RpcSpanTags.METHOD, request.getMethodName()); + serverSpan.setTag(RpcSpanTags.PROTOCOL, (String) request.getRequestProp(HEAD_PROTOCOL)); + serverSpan.setTag(RpcSpanTags.INVOKE_TYPE, (String) request.getRequestProp(HEAD_INVOKE_TYPE)); + serverSpan.setTag(RpcSpanTags.REMOTE_IP, context.getRemoteHostName()); + serverSpan.setTag(RpcSpanTags.REMOTE_APP, (String) request.getRequestProp(HEAD_APP_NAME)); //放到线程上下文 sofaTraceContext.push(serverSpan); //rpc 上下文 if (RpcInternalContext.isAttachmentEnable()) { - RpcInternalContext context = RpcInternalContext.getContext(); context.setAttachment(RpcConstants.INTERNAL_KEY_TRACE_ID, spanContext.getTraceId()); context.setAttachment(RpcConstants.INTERNAL_KEY_SPAN_ID, spanContext.getSpanId()); } @@ -564,6 +576,10 @@ public void serverSend(SofaRequest request, SofaResponse response, Throwable exc RpcInternalContext context = RpcInternalContext.getContext(); RpcInvokeContext invokeContext = RpcInvokeContext.getContext(); + serverSpan.setTag(RpcSpanTags.SERVER_THREAD_POOL_WAIT_TIME, + (Number) context.getAttachment(RpcConstants.INTERNAL_KEY_PROCESS_WAIT_TIME)); + serverSpan.setTag(RpcSpanTags.SERVER_BIZ_TIME, + (Number) RpcInternalContext.getContext().getAttachment(RpcConstants.INTERNAL_KEY_IMPL_ELAPSE)); serverSpan.setTag(RpcSpanTags.RESP_SERIALIZE_TIME, (Number) context.getAttachment(RpcConstants.INTERNAL_KEY_RESP_SERIALIZE_TIME)); serverSpan.setTag(RpcSpanTags.REQ_DESERIALIZE_TIME, diff --git a/tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java b/tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java new file mode 100644 index 000000000..4c46faa73 --- /dev/null +++ b/tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java @@ -0,0 +1,93 @@ +/* + * 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 com.alipay.sofa.rpc.event; + +import com.alipay.common.tracer.core.holder.SofaTraceContextHolder; +import com.alipay.common.tracer.core.span.SofaTracerSpan; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.common.RpcOptions; +import com.alipay.sofa.rpc.context.RpcInternalContext; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.tracer.sofatracer.log.tags.RpcSpanTags; +import io.opentracing.tag.Tags; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Map; + +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_APP_NAME; +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_INVOKE_TYPE; +import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_PROTOCOL; + +/** + * @author Even + * @date 2024/2/27 19:48 + */ +public class SofaTracerSubscriberTest { + + @BeforeClass + public static void beforeClass() { + System.getProperties().put(RpcOptions.DEFAULT_TRACER, "sofaTracer"); + } + + @Test + public void testClientSendAndServerReceiveTracerEvent() { + SofaRequest sofaRequest = new SofaRequest(); + sofaRequest.setMethodName("testService"); + sofaRequest.setTimeout(1000); + sofaRequest.setInvokeType("sync"); + sofaRequest.setTargetServiceUniqueName("testInterface:1.0"); + sofaRequest.setTargetAppName("targetAppName"); + EventBus.post(new ClientStartInvokeEvent(sofaRequest)); + SofaTracerSpan currentClientSpan = SofaTraceContextHolder.getSofaTraceContext().getCurrentSpan(); + Map clientTagsWithStr = currentClientSpan.getTagsWithStr(); + Assert.assertEquals("client", clientTagsWithStr.get(Tags.SPAN_KIND.getKey())); + Assert.assertEquals(sofaRequest.getTargetServiceUniqueName(), clientTagsWithStr.get(RpcSpanTags.SERVICE)); + Assert.assertEquals(sofaRequest.getMethodName(), clientTagsWithStr.get(RpcSpanTags.METHOD)); + Assert.assertEquals(Thread.currentThread().getName(), clientTagsWithStr.get(RpcSpanTags.CURRENT_THREAD_NAME)); + + Assert.assertNull(sofaRequest.getRequestProps()); + EventBus.post(new ClientBeforeSendEvent(sofaRequest)); + Map traceContext = (Map) sofaRequest.getRequestProps().get(RemotingConstants.RPC_TRACE_NAME); + Assert.assertNotNull(traceContext); + + sofaRequest.getRequestProps().put(HEAD_PROTOCOL, "tr"); + sofaRequest.getRequestProps().put(HEAD_INVOKE_TYPE, sofaRequest.getInvokeType()); + sofaRequest.getRequestProps().put(HEAD_APP_NAME, "callerAppName"); + RpcInternalContext.getContext().setRemoteAddress("127.0.0.1", 12200); + EventBus.post(new ServerReceiveEvent(sofaRequest)); + SofaTracerSpan currentServerSpan = SofaTraceContextHolder.getSofaTraceContext().getCurrentSpan(); + Map serverTagsWithStr = currentServerSpan.getTagsWithStr(); + Assert.assertEquals("server", serverTagsWithStr.get(Tags.SPAN_KIND.getKey())); + Assert.assertEquals(sofaRequest.getTargetServiceUniqueName(), serverTagsWithStr.get(RpcSpanTags.SERVICE)); + Assert.assertEquals(sofaRequest.getMethodName(), serverTagsWithStr.get(RpcSpanTags.METHOD)); + Assert.assertEquals(sofaRequest.getTargetAppName(), serverTagsWithStr.get(RpcSpanTags.LOCAL_APP)); + Assert.assertEquals(sofaRequest.getInvokeType(), serverTagsWithStr.get(RpcSpanTags.INVOKE_TYPE)); + Assert.assertEquals("tr", serverTagsWithStr.get(RpcSpanTags.PROTOCOL)); + Assert.assertEquals("127.0.0.1", serverTagsWithStr.get(RpcSpanTags.REMOTE_IP)); + Assert.assertEquals("callerAppName", serverTagsWithStr.get(RpcSpanTags.REMOTE_APP)); + SofaTraceContextHolder.getSofaTraceContext().clear(); + } + + @AfterClass + public static void afterClass() { + System.getProperties().remove(RpcOptions.DEFAULT_TRACER); + } + +} \ No newline at end of file From e67ea542b414de26eae6a759e85ea7f5dff35b6c Mon Sep 17 00:00:00 2001 From: evenliu Date: Wed, 27 Mar 2024 16:55:21 +0800 Subject: [PATCH 27/64] fix test case error (#1407) Co-authored-by: liujianjun.ljj --- .../sofatracer}/SofaTracerSubscriberTest.java | 19 +++++-------------- .../test/resources/sofa-rpc/rpc-config.json | 3 ++- 2 files changed, 7 insertions(+), 15 deletions(-) rename {tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event => test/test-integration/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer}/SofaTracerSubscriberTest.java (91%) diff --git a/tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/SofaTracerSubscriberTest.java similarity index 91% rename from tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java rename to test/test-integration/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/SofaTracerSubscriberTest.java index 4c46faa73..5f9b78b84 100644 --- a/tracer/tracer-opentracing/src/test/java/com/alipay/sofa/rpc/event/SofaTracerSubscriberTest.java +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/SofaTracerSubscriberTest.java @@ -14,19 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alipay.sofa.rpc.event; +package com.alipay.sofa.rpc.tracer.sofatracer; import com.alipay.common.tracer.core.holder.SofaTraceContextHolder; import com.alipay.common.tracer.core.span.SofaTracerSpan; import com.alipay.sofa.rpc.common.RemotingConstants; -import com.alipay.sofa.rpc.common.RpcOptions; import com.alipay.sofa.rpc.context.RpcInternalContext; import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.event.ClientBeforeSendEvent; +import com.alipay.sofa.rpc.event.ClientStartInvokeEvent; +import com.alipay.sofa.rpc.event.EventBus; +import com.alipay.sofa.rpc.event.ServerReceiveEvent; import com.alipay.sofa.rpc.tracer.sofatracer.log.tags.RpcSpanTags; import io.opentracing.tag.Tags; -import org.junit.AfterClass; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import java.util.Map; @@ -41,11 +42,6 @@ */ public class SofaTracerSubscriberTest { - @BeforeClass - public static void beforeClass() { - System.getProperties().put(RpcOptions.DEFAULT_TRACER, "sofaTracer"); - } - @Test public void testClientSendAndServerReceiveTracerEvent() { SofaRequest sofaRequest = new SofaRequest(); @@ -85,9 +81,4 @@ public void testClientSendAndServerReceiveTracerEvent() { SofaTraceContextHolder.getSofaTraceContext().clear(); } - @AfterClass - public static void afterClass() { - System.getProperties().remove(RpcOptions.DEFAULT_TRACER); - } - } \ No newline at end of file diff --git a/test/test-integration/src/test/resources/sofa-rpc/rpc-config.json b/test/test-integration/src/test/resources/sofa-rpc/rpc-config.json index 5b573549a..786432c70 100644 --- a/test/test-integration/src/test/resources/sofa-rpc/rpc-config.json +++ b/test/test-integration/src/test/resources/sofa-rpc/rpc-config.json @@ -1,4 +1,5 @@ { "rpc.config.order": 999, - "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl" + "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl", + "default.tracer": "sofaTracer" } \ No newline at end of file From a97d72c10622759b23b8a0292a4b073eb5ed68cb Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Thu, 28 Mar 2024 11:31:13 +0800 Subject: [PATCH 28/64] Enhanced for Nacos weight configuration (#1406) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 呈铭 --- .../registry/nacos/NacosRegistryHelper.java | 7 +++ .../nacos/NacosRegistryHelperTest.java | 59 ++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelper.java b/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelper.java index 2951edb8e..4fcb9f8a3 100644 --- a/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelper.java +++ b/registry/registry-nacos/src/main/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelper.java @@ -123,6 +123,13 @@ static List convertInstancesToProviders(List allInstance for (Instance instance : allInstances) { String url = convertInstanceToUrl(instance); ProviderInfo providerInfo = ProviderHelper.toProviderInfo(url); + + // Nacos的默认权重为1.0 + // 当Nacos默认权重传入1.0,根据代码逻辑计算结果为100,与sofa-rpc默认权重一致 + // 因为是接口级别,如果不同的服务具有不同的权重也不会出现被覆盖或者冲突的情况 + long weight = Math.round(providerInfo.getWeight() * instance.getWeight()); + providerInfo.setWeight(Math.round(weight)); + providerInfos.add(providerInfo); } return providerInfos; diff --git a/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelperTest.java b/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelperTest.java index 8a38cbf0e..385ee3dab 100644 --- a/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelperTest.java +++ b/registry/registry-nacos/src/test/java/com/alipay/sofa/rpc/registry/nacos/NacosRegistryHelperTest.java @@ -136,4 +136,61 @@ public void buildServiceName() { serviceName = NacosRegistryHelper.buildServiceName(provider, RpcConstants.PROTOCOL_TYPE_REST); assertEquals(serviceName, "com.alipay.xxx.TestService:nacos-test:" + RpcConstants.PROTOCOL_TYPE_REST); } -} \ No newline at end of file + + @Test + public void testNacosWeight() { + Instance instance = new Instance(); + instance.setClusterName(NacosRegistryHelper.DEFAULT_CLUSTER); + instance.setIp("1.1.1.1"); + instance.setPort(12200); + instance.setServiceName("com.alipay.xxx.TestService"); + instance.setWeight(0.99D); + + List providerInfos = NacosRegistryHelper + .convertInstancesToProviders(Lists.newArrayList(instance)); + assertNotNull(providerInfos); + assertEquals(1, providerInfos.size()); + + ProviderInfo providerInfo = providerInfos.get(0); + assertNotNull(providerInfo); + assertEquals(99, providerInfo.getWeight()); + } + + @Test + public void testNacosWeightLessThan0() { + Instance instance = new Instance(); + instance.setClusterName(NacosRegistryHelper.DEFAULT_CLUSTER); + instance.setIp("1.1.1.1"); + instance.setPort(12200); + instance.setServiceName("com.alipay.xxx.TestService"); + instance.setWeight(-0.1D); + + List providerInfos = NacosRegistryHelper + .convertInstancesToProviders(Lists.newArrayList(instance)); + assertNotNull(providerInfos); + assertEquals(1, providerInfos.size()); + + ProviderInfo providerInfo = providerInfos.get(0); + assertNotNull(providerInfo); + assertEquals(-10, providerInfo.getWeight()); + } + + @Test + public void testNacosWeightWith0() { + Instance instance = new Instance(); + instance.setClusterName(NacosRegistryHelper.DEFAULT_CLUSTER); + instance.setIp("1.1.1.1"); + instance.setPort(12200); + instance.setServiceName("com.alipay.xxx.TestService"); + instance.setWeight(0.0D); + + List providerInfos = NacosRegistryHelper + .convertInstancesToProviders(Lists.newArrayList(instance)); + assertNotNull(providerInfos); + assertEquals(1, providerInfos.size()); + + ProviderInfo providerInfo = providerInfos.get(0); + assertNotNull(providerInfo); + assertEquals(0, providerInfo.getWeight()); + } +} From f4a18df07fcd4cb99bc68725ee6eba0f9ae5ce65 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 15 Apr 2024 17:23:54 +0800 Subject: [PATCH 29/64] enhance: bump hessian from 3.5.2 to 3.5.3 (#1409) Co-authored-by: Lo1nt --- all/pom.xml | 2 +- bom/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index df0690331..3837b5bbb 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -59,7 +59,7 @@ 1.3.15 3.29.2-GA 4.1.44.Final - 3.5.2 + 3.5.3 3.6.3.Final 1.6.6 3.0.8 diff --git a/bom/pom.xml b/bom/pom.xml index d43a6183d..9325490d5 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -32,7 +32,7 @@ 32.0.0-jre 0.16.0 - 3.5.2 + 3.5.3 0.9.2 3.22.0 2.12.7 From ddd63ab531ff8e1f56f6e8c055919e44c20b3b73 Mon Sep 17 00:00:00 2001 From: evenliu Date: Tue, 30 Apr 2024 16:23:21 +0800 Subject: [PATCH 30/64] add additional source directories for triple (#1412) Co-authored-by: liujianjun.ljj --- pom.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pom.xml b/pom.xml index ad0a95221..eead098ca 100644 --- a/pom.xml +++ b/pom.xml @@ -192,6 +192,25 @@ + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + generate-sources + + add-source + + + + build/generated/source/proto/main/java + + + + + + org.apache.maven.plugins maven-jar-plugin From cd8bb17117d9d1e838dabb27950b8fc5dc56c772 Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 10 May 2024 15:16:06 +0800 Subject: [PATCH 31/64] fix baggage do not pick up to RpcInvokeContext problem (#1402) Co-authored-by: liujianjun.ljj --- .../alipay/sofa/rpc/codec/bolt/SofaRpcSerialization.java | 3 +++ .../sofa/rpc/codec/bolt/SofaRpcSerializationTest.java | 9 +++++++++ .../src/test/resources/sofa-rpc/rpc-config.json | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerialization.java b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerialization.java index 655c8fd87..297243824 100644 --- a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerialization.java +++ b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerialization.java @@ -312,6 +312,9 @@ protected void parseRequestHeader(Map headerMap, Object sofaRequ if (sofaRequest instanceof SofaRequest) { // 处理 tracer parseRequestHeader(RemotingConstants.RPC_TRACE_NAME, headerMap, (SofaRequest) sofaRequest); + if (RpcInvokeContext.isBaggageEnable()) { + parseRequestHeader(RemotingConstants.RPC_REQUEST_BAGGAGE, headerMap, (SofaRequest) sofaRequest); + } Map requestProps = ((SofaRequest) sofaRequest).getRequestProps(); if (requestProps == null) { for (Map.Entry entry : headerMap.entrySet()) { diff --git a/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerializationTest.java b/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerializationTest.java index 646f12200..2283ec307 100644 --- a/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerializationTest.java +++ b/remoting/remoting-bolt/src/test/java/com/alipay/sofa/rpc/codec/bolt/SofaRpcSerializationTest.java @@ -25,6 +25,7 @@ import com.alipay.sofa.rpc.core.request.SofaRequest; import org.junit.Assert; import org.junit.Test; + import java.util.HashMap; import java.util.Map; @@ -92,16 +93,24 @@ public void testParseRequestHeader(){ headerMap.put("testKey1","testValue1"); headerMap.put("rpc_trace_context.sofaTraceId", "traceId"); headerMap.put("rpc_trace_context.sofaRpcId", "rpcId"); + headerMap.put("rpc_req_baggage.testBaggageKey1", "testBaggageValue1"); + headerMap.put("rpc_req_baggage.testBaggageKey2", "testBaggageValue2"); SofaRpcSerialization sofaRpcSerialization = new SofaRpcSerialization(); SofaRequest sofaRequest = new SofaRequest(); sofaRequest.addRequestProp("testKey1", "testValue11"); sofaRequest.addRequestProp("testKey2", "testValue2"); sofaRpcSerialization.parseRequestHeader(headerMap, sofaRequest); + sofaRpcSerialization.parseRequestHeader(headerMap, sofaRequest); Assert.assertEquals("testValue1", sofaRequest.getRequestProp("testKey1")); Assert.assertEquals("testValue2", sofaRequest.getRequestProp("testKey2")); Object traceMap = sofaRequest.getRequestProp(RemotingConstants.RPC_TRACE_NAME); Assert.assertTrue(traceMap instanceof Map); Assert.assertEquals("traceId",((Map)traceMap).get("sofaTraceId")); Assert.assertEquals("rpcId",((Map)traceMap).get("sofaRpcId")); + Object baggageMap = sofaRequest.getRequestProp(RemotingConstants.RPC_REQUEST_BAGGAGE); + Assert.assertTrue(baggageMap instanceof Map); + Assert.assertEquals("testBaggageValue1", ((Map) baggageMap).get("testBaggageKey1")); + Assert.assertEquals("testBaggageValue2", ((Map) baggageMap).get("testBaggageKey2")); + } } \ No newline at end of file diff --git a/remoting/remoting-bolt/src/test/resources/sofa-rpc/rpc-config.json b/remoting/remoting-bolt/src/test/resources/sofa-rpc/rpc-config.json index 5b573549a..edd0e9cb4 100644 --- a/remoting/remoting-bolt/src/test/resources/sofa-rpc/rpc-config.json +++ b/remoting/remoting-bolt/src/test/resources/sofa-rpc/rpc-config.json @@ -1,4 +1,5 @@ { "rpc.config.order": 999, - "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl" + "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl", + "invoke.baggage.enable": true } \ No newline at end of file From 279ea0d15a998b6fdad72e7c2f09b9b6e87f2eda Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Fri, 10 May 2024 15:17:02 +0800 Subject: [PATCH 32/64] Support bzip2 and gzip compress (#1399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * support for https://github.com/sofastack/sofa-rpc/issues/1398 Co-authored-by: 呈铭 Co-authored-by: evenliu Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- all/pom.xml | 6 ++ bom/pom.xml | 10 ++- codec/codec-api/pom.xml | 5 ++ .../rpc/codec/bzip2/Bzip2RpcCompressor.java | 76 +++++++++++++++++++ .../rpc/codec/gzip/GzipRpcCompressor.java | 70 +++++++++++++++++ .../com.alipay.sofa.rpc.codec.Compressor | 4 +- .../codec/bzip2/Bzip2RpcCompressorTest.java | 53 +++++++++++++ .../rpc/codec/gzip/GzipRpcCompressorTest.java | 54 +++++++++++++ 8 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressor.java create mode 100644 codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressor.java create mode 100644 codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressorTest.java create mode 100644 codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressorTest.java diff --git a/all/pom.xml b/all/pom.xml index 3837b5bbb..a8af0e0fa 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -74,6 +74,7 @@ 32.0.0-jre 2.12.1 0.4.1 + 1.25.0 @@ -445,6 +446,11 @@ fury-core ${fury.version} + + org.apache.commons + commons-compress + ${commons_compress_version} + diff --git a/bom/pom.xml b/bom/pom.xml index 9325490d5..be44d0ed8 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -62,6 +62,7 @@ true 6.9.2 + 1.25.0 @@ -515,7 +516,6 @@ grpc-stub ${grpc.version} - io.fabric8 @@ -529,6 +529,8 @@ ${fabric8_kubernetes_version} + + org.apache.curator @@ -613,6 +615,12 @@ 0.16.0 test + + + org.apache.commons + commons-compress + ${commons_compress_version} + diff --git a/codec/codec-api/pom.xml b/codec/codec-api/pom.xml index 47b42b4fe..921fa0e31 100644 --- a/codec/codec-api/pom.xml +++ b/codec/codec-api/pom.xml @@ -38,6 +38,11 @@ junit test + + + org.apache.commons + commons-compress + diff --git a/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressor.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressor.java new file mode 100644 index 000000000..86993b037 --- /dev/null +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressor.java @@ -0,0 +1,76 @@ +/* + * 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 com.alipay.sofa.rpc.codec.bzip2; + +import com.alipay.sofa.rpc.codec.Compressor; +import com.alipay.sofa.rpc.ext.Extension; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +/** + * bzip2 compressor, faster compression efficiency + * + * @author chengming + * @version Bzip2RpcCompressor.java, v 0.1 2024年02月28日 10:45 AM chengming + * @link https://commons.apache.org/proper/commons-compress/ + */ +@Extension(value = "bzip2", code = 3) +public class Bzip2RpcCompressor implements Compressor { + + @Override + public byte[] compress(byte[] src) { + if (null == src || 0 == src.length) { + return new byte[0]; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + BZip2CompressorOutputStream cos; + try { + cos = new BZip2CompressorOutputStream(out); + cos.write(src); + cos.close(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + + return out.toByteArray(); + } + + @Override + public byte[] deCompress(byte[] src) { + if (null == src || 0 == src.length) { + return new byte[0]; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(src); + try { + BZip2CompressorInputStream unZip = new BZip2CompressorInputStream(in); + byte[] buffer = new byte[2048]; + int n; + while ((n = unZip.read(buffer)) >= 0) { + out.write(buffer, 0, n); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + return out.toByteArray(); + } +} \ No newline at end of file diff --git a/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressor.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressor.java new file mode 100644 index 000000000..5f68209db --- /dev/null +++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressor.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 com.alipay.sofa.rpc.codec.gzip; + +import com.alipay.sofa.rpc.codec.Compressor; +import com.alipay.sofa.rpc.ext.Extension; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * @author chengming + * @version GzipRpcCompressor.java, v 0.1 2024年02月28日 11:25 AM chengming + */ +@Extension(value = "gzip", code = 4) +public class GzipRpcCompressor implements Compressor { + + @Override + public byte[] compress(byte[] src) { + if (null == src || 0 == src.length) { + return new byte[0]; + } + + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteOutStream)) { + gzipOutputStream.write(src); + } catch (Exception exception) { + throw new IllegalStateException(exception); + } + + return byteOutStream.toByteArray(); + } + + @Override + public byte[] deCompress(byte[] src) { + if (null == src || 0 == src.length) { + return new byte[0]; + } + + ByteArrayInputStream byteInStream = new ByteArrayInputStream(src); + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + try (GZIPInputStream gzipInputStream = new GZIPInputStream(byteInStream)) { + int readByteNum; + byte[] bufferArr = new byte[256]; + while ((readByteNum = gzipInputStream.read(bufferArr)) >= 0) { + byteOutStream.write(bufferArr, 0, readByteNum); + } + } catch (Exception exception) { + throw new IllegalStateException(exception); + } + + return byteOutStream.toByteArray(); + } +} \ No newline at end of file diff --git a/codec/codec-api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Compressor b/codec/codec-api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Compressor index a0d34faa1..84b01a049 100644 --- a/codec/codec-api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Compressor +++ b/codec/codec-api/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Compressor @@ -1 +1,3 @@ -snappy=com.alipay.sofa.rpc.codec.snappy.SnappyRpcCompressor \ No newline at end of file +snappy=com.alipay.sofa.rpc.codec.snappy.SnappyRpcCompressor +bzip2=com.alipay.sofa.rpc.codec.bzip2.Bzip2RpcCompressor +gzip=com.alipay.sofa.rpc.codec.gzip.GzipRpcCompressor \ No newline at end of file diff --git a/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressorTest.java b/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressorTest.java new file mode 100644 index 000000000..c82ebc2a1 --- /dev/null +++ b/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/bzip2/Bzip2RpcCompressorTest.java @@ -0,0 +1,53 @@ +/* + * 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 com.alipay.sofa.rpc.codec.bzip2; + +import com.alipay.sofa.rpc.codec.Compressor; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +/** + * @author chengming + * @version Bzip2RpcCompressorTest.java, v 0.1 2024年02月28日 2:19 PM chengming + */ +public class Bzip2RpcCompressorTest { + + private static final String TEST_STR; + + static { + StringBuilder builder = new StringBuilder(); + int charNum = 1000000; + for (int i = 0; i < charNum; i++) { + builder.append("a"); + } + + TEST_STR = builder.toString(); + } + + @Test + public void testCompression() throws UnsupportedEncodingException { + Compressor compressor = ExtensionLoaderFactory.getExtensionLoader(Compressor.class).getExtension("bzip2"); + Assert.assertTrue(compressor instanceof Bzip2RpcCompressor); + + byte[] bs = compressor.compress(TEST_STR.getBytes("utf-8")); + String s1 = new String(compressor.deCompress(bs), "utf-8"); + Assert.assertEquals(TEST_STR, s1); + } +} \ No newline at end of file diff --git a/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressorTest.java b/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressorTest.java new file mode 100644 index 000000000..694b14e78 --- /dev/null +++ b/codec/codec-api/src/test/java/com/alipay/sofa/rpc/codec/gzip/GzipRpcCompressorTest.java @@ -0,0 +1,54 @@ +/* + * 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 com.alipay.sofa.rpc.codec.gzip; + +import com.alipay.sofa.rpc.codec.Compressor; +import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +/** + * @author chengming + * @version GzipRpcCompressorTest.java, v 0.1 2024年02月28日 2:09 PM chengming + */ +public class GzipRpcCompressorTest { + + private static final String TEST_STR; + + static { + StringBuilder builder = new StringBuilder(); + int charNum = 1000000; + for (int i = 0; i < charNum; i++) { + builder.append("a"); + } + + TEST_STR = builder.toString(); + } + + @Test + public void testCompression() throws UnsupportedEncodingException { + Compressor compressor = ExtensionLoaderFactory.getExtensionLoader(Compressor.class).getExtension("gzip"); + Assert.assertTrue(compressor instanceof GzipRpcCompressor); + + byte[] bs = compressor.compress(TEST_STR.getBytes("utf-8")); + String s1 = new String(compressor.deCompress(bs), "utf-8"); + Assert.assertEquals(TEST_STR, s1); + } + +} From ccb613cad6893be0564021e817914b5e1ba411f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:18:32 +0800 Subject: [PATCH 33/64] chore(deps): bump org.apache.cxf:cxf-core from 3.4.10 to 3.5.8 in /bom (#1404) Bumps org.apache.cxf:cxf-core from 3.4.10 to 3.5.8. --- updated-dependencies: - dependency-name: org.apache.cxf:cxf-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index be44d0ed8..680de8b19 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -18,7 +18,7 @@ 2.5 3.6.3.Final 1.0.2.Final - 3.4.10 + 3.5.8 7.5.4.v20111024 3.5.7 4.3.0 From 201efe3228050a9d971d1e347fd8caa24fda9e84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:38:54 +0800 Subject: [PATCH 34/64] chore(deps): bump org.apache.commons:commons-compress in /bom (#1413) Bumps org.apache.commons:commons-compress from 1.25.0 to 1.26.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-compress dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 680de8b19..4ce1bd589 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -62,7 +62,7 @@ true 6.9.2 - 1.25.0 + 1.26.0 From 12fbfe15836b3bbcdb58047c2210459a70e1b5aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:40:58 +0800 Subject: [PATCH 35/64] chore(deps): bump org.apache.commons:commons-compress in /all (#1414) Bumps org.apache.commons:commons-compress from 1.25.0 to 1.26.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-compress dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- all/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/all/pom.xml b/all/pom.xml index a8af0e0fa..271a754f1 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -74,7 +74,7 @@ 32.0.0-jre 2.12.1 0.4.1 - 1.25.0 + 1.26.0 From 56ed259aba0ff65450c0a622786a5b076a1707e8 Mon Sep 17 00:00:00 2001 From: namelessssssssssss <100946116+namelessssssssssss@users.noreply.github.com> Date: Tue, 14 May 2024 10:05:12 +0800 Subject: [PATCH 36/64] Triple stream support (issue#1332) (#1360) * Add bi-stream call support for triple * triple pojo mode support stream --------- Co-authored-by: liujianjun.ljj --- .../alipay/sofa/rpc/common/RpcConstants.java | 16 + .../rpc/transport/SofaStreamObserver.java | 48 ++ .../sofa/rpc/core/exception/RpcErrorType.java | 5 + .../proto/main/java/triple/GenericProto.java | 9 +- .../main/java/triple/GenericServiceGrpc.java | 125 ++++++ .../java/triple/SofaGenericServiceTriple.java | 62 +++ .../stream/ClientStreamObserverAdapter.java | 71 +++ .../ResponseSerializeSofaStreamObserver.java | 72 +++ .../rpc/server/triple/GenericServiceImpl.java | 195 ++++++++- .../sofa/rpc/server/triple/TripleServer.java | 39 +- .../rpc/server/triple/UniqueIdInvoker.java | 19 +- .../transport/triple/TripleClientInvoker.java | 209 ++++++--- .../alipay/sofa/rpc/utils/SofaProtoUtils.java | 84 ++++ .../sofa/rpc/utils/TripleExceptionUtils.java | 32 ++ .../src/main/proto/transformer.proto | 5 + .../server/triple/GenericServiceImplTest.java | 5 +- .../src/main/proto/helloworld.proto | 6 + .../sofa/rpc/test/triple/GreeterImpl.java | 76 +++- .../test/triple/NativeGrpcGreeterImpl.java | 127 ++++++ .../rpc/test/triple/stream/ClientRequest.java | 36 ++ .../triple/stream/ExtendClientRequest.java | 39 ++ .../triple/stream/ExtendServerResponse.java | 39 ++ .../rpc/test/triple/stream/HelloService.java | 32 ++ .../test/triple/stream/HelloServiceImpl.java | 81 ++++ .../test/triple/stream/ServerResponse.java | 36 ++ .../stream/TripleGenericStreamTest.java | 224 ++++++++++ .../triple/stream/TripleStubStreamTest.java | 413 ++++++++++++++++++ 27 files changed, 2001 insertions(+), 104 deletions(-) create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/transport/SofaStreamObserver.java create mode 100644 remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java create mode 100644 remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ResponseSerializeSofaStreamObserver.java create mode 100644 remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/NativeGrpcGreeterImpl.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ClientRequest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendClientRequest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendServerResponse.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ServerResponse.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleStubStreamTest.java diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java index b09cdfe7f..8c77e3223 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java @@ -121,6 +121,22 @@ public class RpcConstants { * 调用方式:future */ public static final String INVOKER_TYPE_FUTURE = "future"; + /** + * 调用方式:一元调用 + */ + public static final String INVOKER_TYPE_UNARY = "unary"; + /** + * 调用方式:客户端流 + */ + public static final String INVOKER_TYPE_CLIENT_STREAMING = "clientStream"; + /** + * 调用方式:服务端流 + */ + public static final String INVOKER_TYPE_SERVER_STREAMING = "serverStream"; + /** + * 调用方式:双向流 + */ + public static final String INVOKER_TYPE_BI_STREAMING = "bidirectionalStream"; /** * Hessian序列化 [不推荐] diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/transport/SofaStreamObserver.java b/core/api/src/main/java/com/alipay/sofa/rpc/transport/SofaStreamObserver.java new file mode 100644 index 000000000..c841e5edc --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/transport/SofaStreamObserver.java @@ -0,0 +1,48 @@ +/* + * 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 com.alipay.sofa.rpc.transport; + +/** + * StreamHandler, works just like gRPC StreamObserver. + */ +public interface SofaStreamObserver { + + /** + * Sends a message, or defines the behavior when a message is received. + *

This method should never be called after {@link SofaStreamObserver#onCompleted()} has been invoked. + */ + void onNext(T message); + + /** + * Note: This method MUST be invoked after the transport is complete. + * Failure to do so may result in unexpected errors. + *

+ * Signals that all messages have been sent/received normally, and closes this stream. + */ + void onCompleted(); + + /** + * Signals an exception to terminate this stream, or defines the behavior when an error occurs. + *

+ * Once this method is invoked by one side, it can't send more messages, and the corresponding method on the other side will be triggered. + * Depending on the protocol implementation, it's possible that the other side can still call {@link SofaStreamObserver#onNext(Object)} after this method has been invoked, although this is not recommended. + *

+ * As a best practice, it is advised not to send any more information once this method is called. + * + */ + void onError(Throwable throwable); +} diff --git a/core/exception/src/main/java/com/alipay/sofa/rpc/core/exception/RpcErrorType.java b/core/exception/src/main/java/com/alipay/sofa/rpc/core/exception/RpcErrorType.java index 5356e1bbd..937165e29 100644 --- a/core/exception/src/main/java/com/alipay/sofa/rpc/core/exception/RpcErrorType.java +++ b/core/exception/src/main/java/com/alipay/sofa/rpc/core/exception/RpcErrorType.java @@ -93,6 +93,11 @@ public class RpcErrorType { */ public static final int CLIENT_NETWORK = 250; + /** + * 不支持的RPC调用方式异常 + */ + public static final int CLIENT_CALL_TYPE = 260; + /** * 客户端过滤器异常 */ diff --git a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericProto.java b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericProto.java index 808f3a3a7..37f91d33e 100644 --- a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericProto.java +++ b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericProto.java @@ -36,9 +36,12 @@ public static void registerAllExtensions( "\n\021transformer.proto\"@\n\007Request\022\025\n\rserial" + "izeType\030\001 \001(\t\022\014\n\004args\030\002 \003(\014\022\020\n\010argTypes\030" + "\003 \003(\t\"=\n\010Response\022\025\n\rserializeType\030\001 \001(\t" + - "\022\014\n\004data\030\002 \001(\014\022\014\n\004type\030\003 \001(\t22\n\016GenericS" + - "ervice\022 \n\007generic\022\010.Request\032\t.Response\"\000" + - "B\030\n\006tripleB\014GenericProtoP\001b\006proto3" + "\022\014\n\004data\030\002 \001(\014\022\014\n\004type\030\003 \001(\t2\220\001\n\016Generic" + + "Service\022 \n\007generic\022\010.Request\032\t.Response\"" + + "\000\022,\n\017genericBiStream\022\010.Request\032\t.Respons" + + "e\"\000(\0010\001\022.\n\023genericServerStream\022\010.Request" + + "\032\t.Response\"\0000\001B\030\n\006tripleB\014GenericProtoP" + + "\001b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, diff --git a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericServiceGrpc.java b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericServiceGrpc.java index 75a2e5ba5..27d1c02c6 100644 --- a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericServiceGrpc.java +++ b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/GenericServiceGrpc.java @@ -46,6 +46,68 @@ triple.Response> getGenericMethod() { return getGenericMethod; } + private static volatile io.grpc.MethodDescriptor getGenericBiStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "genericBiStream", + requestType = triple.Request.class, + responseType = triple.Response.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getGenericBiStreamMethod() { + io.grpc.MethodDescriptor getGenericBiStreamMethod; + if ((getGenericBiStreamMethod = GenericServiceGrpc.getGenericBiStreamMethod) == null) { + synchronized (GenericServiceGrpc.class) { + if ((getGenericBiStreamMethod = GenericServiceGrpc.getGenericBiStreamMethod) == null) { + GenericServiceGrpc.getGenericBiStreamMethod = getGenericBiStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "genericBiStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + triple.Request.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + triple.Response.getDefaultInstance())) + .setSchemaDescriptor(new GenericServiceMethodDescriptorSupplier("genericBiStream")) + .build(); + } + } + } + return getGenericBiStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getGenericServerStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "genericServerStream", + requestType = triple.Request.class, + responseType = triple.Response.class, + methodType = io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + public static io.grpc.MethodDescriptor getGenericServerStreamMethod() { + io.grpc.MethodDescriptor getGenericServerStreamMethod; + if ((getGenericServerStreamMethod = GenericServiceGrpc.getGenericServerStreamMethod) == null) { + synchronized (GenericServiceGrpc.class) { + if ((getGenericServerStreamMethod = GenericServiceGrpc.getGenericServerStreamMethod) == null) { + GenericServiceGrpc.getGenericServerStreamMethod = getGenericServerStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "genericServerStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + triple.Request.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + triple.Response.getDefaultInstance())) + .setSchemaDescriptor(new GenericServiceMethodDescriptorSupplier("genericServerStream")) + .build(); + } + } + } + return getGenericServerStreamMethod; + } + /** * Creates a new async stub that supports all call types for the service */ @@ -101,6 +163,20 @@ public void generic(triple.Request request, io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGenericMethod(), responseObserver); } + /** + */ + public io.grpc.stub.StreamObserver genericBiStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getGenericBiStreamMethod(), responseObserver); + } + + /** + */ + public void genericServerStream(triple.Request request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGenericServerStreamMethod(), responseObserver); + } + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( @@ -110,6 +186,20 @@ public void generic(triple.Request request, triple.Request, triple.Response>( this, METHODID_GENERIC))) + .addMethod( + getGenericBiStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + triple.Request, + triple.Response>( + this, METHODID_GENERIC_BI_STREAM))) + .addMethod( + getGenericServerStreamMethod(), + io.grpc.stub.ServerCalls.asyncServerStreamingCall( + new MethodHandlers< + triple.Request, + triple.Response>( + this, METHODID_GENERIC_SERVER_STREAM))) .build(); } } @@ -135,6 +225,22 @@ public void generic(triple.Request request, io.grpc.stub.ClientCalls.asyncUnaryCall( getChannel().newCall(getGenericMethod(), getCallOptions()), request, responseObserver); } + + /** + */ + public io.grpc.stub.StreamObserver genericBiStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getGenericBiStreamMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void genericServerStream(triple.Request request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncServerStreamingCall( + getChannel().newCall(getGenericServerStreamMethod(), getCallOptions()), request, responseObserver); + } } /** @@ -157,6 +263,14 @@ public triple.Response generic(triple.Request request) { return io.grpc.stub.ClientCalls.blockingUnaryCall( getChannel(), getGenericMethod(), getCallOptions(), request); } + + /** + */ + public java.util.Iterator genericServerStream( + triple.Request request) { + return io.grpc.stub.ClientCalls.blockingServerStreamingCall( + getChannel(), getGenericServerStreamMethod(), getCallOptions(), request); + } } /** @@ -183,6 +297,8 @@ public com.google.common.util.concurrent.ListenableFuture gener } private static final int METHODID_GENERIC = 0; + private static final int METHODID_GENERIC_SERVER_STREAM = 1; + private static final int METHODID_GENERIC_BI_STREAM = 2; private static final class MethodHandlers implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -205,6 +321,10 @@ public void invoke(Req request, io.grpc.stub.StreamObserver responseObserv serviceImpl.generic((triple.Request) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_GENERIC_SERVER_STREAM: + serviceImpl.genericServerStream((triple.Request) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new AssertionError(); } @@ -215,6 +335,9 @@ public void invoke(Req request, io.grpc.stub.StreamObserver responseObserv public io.grpc.stub.StreamObserver invoke( io.grpc.stub.StreamObserver responseObserver) { switch (methodId) { + case METHODID_GENERIC_BI_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.genericBiStream( + (io.grpc.stub.StreamObserver) responseObserver); default: throw new AssertionError(); } @@ -267,6 +390,8 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() { serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) .setSchemaDescriptor(new GenericServiceFileDescriptorSupplier()) .addMethod(getGenericMethod()) + .addMethod(getGenericBiStreamMethod()) + .addMethod(getGenericServerStreamMethod()) .build(); } } diff --git a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/SofaGenericServiceTriple.java b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/SofaGenericServiceTriple.java index 0eb60e668..94f2b52bc 100644 --- a/remoting/remoting-triple/build/generated/source/proto/main/java/triple/SofaGenericServiceTriple.java +++ b/remoting/remoting-triple/build/generated/source/proto/main/java/triple/SofaGenericServiceTriple.java @@ -50,6 +50,23 @@ public void generic(triple.Request request, io.grpc.stub.StreamObserver genericServerStream(triple.Request request) { + return blockingStub + .withDeadlineAfter(timeout, TimeUnit.MILLISECONDS) + .genericServerStream(request); + } + + public void genericServerStream(triple.Request request, io.grpc.stub.StreamObserver responseObserver) { + stub + .withDeadlineAfter(timeout, TimeUnit.MILLISECONDS) + .genericServerStream(request, responseObserver); + } + + public io.grpc.stub.StreamObserver genericBiStream(io.grpc.stub.StreamObserver responseObserver) { + return stub + .withDeadlineAfter(timeout, TimeUnit.MILLISECONDS) + .genericBiStream(responseObserver); + } } public static SofaGenericServiceStub getSofaStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions,int timeout) { @@ -71,6 +88,14 @@ default public com.google.common.util.concurrent.ListenableFuture responseObserver); + default public java.util.Iterator genericServerStream(triple.Request request) { + throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); + } + + public void genericServerStream(triple.Request request, io.grpc.stub.StreamObserver responseObserver); + + public io.grpc.stub.StreamObserver genericBiStream(io.grpc.stub.StreamObserver responseObserver); + } public static abstract class GenericServiceImplBase implements io.grpc.BindableService, IGenericService { @@ -89,12 +114,25 @@ public final triple.Response generic(triple.Request request) { @java.lang.Override public final com.google.common.util.concurrent.ListenableFuture genericAsync(triple.Request request) { throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); + } + + @java.lang.Override + public final java.util.Iterator genericServerStream(triple.Request request) { + throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); } public void generic(triple.Request request, io.grpc.stub.StreamObserver responseObserver) { asyncUnimplementedUnaryCall(triple.GenericServiceGrpc.getGenericMethod(), responseObserver); } + public io.grpc.stub.StreamObserver genericBiStream( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(triple.GenericServiceGrpc.getGenericBiStreamMethod(), responseObserver); + } + public void genericServerStream(triple.Request request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(triple.GenericServiceGrpc.getGenericServerStreamMethod(), responseObserver); + } @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) @@ -105,10 +143,26 @@ public void generic(triple.Request request, triple.Request, triple.Response>( proxiedImpl, METHODID_GENERIC))) + .addMethod( + triple.GenericServiceGrpc.getGenericBiStreamMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + triple.Request, + triple.Response>( + proxiedImpl, METHODID_GENERIC_BI_STREAM))) + .addMethod( + triple.GenericServiceGrpc.getGenericServerStreamMethod(), + asyncServerStreamingCall( + new MethodHandlers< + triple.Request, + triple.Response>( + proxiedImpl, METHODID_GENERIC_SERVER_STREAM))) .build(); } } private static final int METHODID_GENERIC = 0; + private static final int METHODID_GENERIC_BI_STREAM = 1; + private static final int METHODID_GENERIC_SERVER_STREAM = 2; private static final class MethodHandlers implements @@ -137,6 +191,10 @@ public void invoke(Req request, io.grpc.stub.StreamObserver serviceImpl.generic((triple.Request) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_GENERIC_SERVER_STREAM: + serviceImpl.genericServerStream((triple.Request) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new java.lang.AssertionError(); } @@ -148,6 +206,10 @@ public void invoke(Req request, io.grpc.stub.StreamObserver invoke(io.grpc.stub.StreamObserver responseObserver) { switch (methodId) { + case METHODID_GENERIC_BI_STREAM: + return (io.grpc.stub.StreamObserver + ) serviceImpl.genericBiStream( + (io.grpc.stub.StreamObserver) responseObserver); default: throw new java.lang.AssertionError(); } diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java new file mode 100644 index 000000000..72fbf75ff --- /dev/null +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java @@ -0,0 +1,71 @@ +/* + * 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 com.alipay.sofa.rpc.message.triple.stream; + +import com.alipay.sofa.rpc.codec.Serializer; +import com.alipay.sofa.rpc.codec.SerializerFactory; +import com.alipay.sofa.rpc.core.exception.RpcErrorType; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; +import io.grpc.stub.StreamObserver; + +/** + * ClientStreamObserverAdapter. + */ +public class ClientStreamObserverAdapter implements StreamObserver { + + private final SofaStreamObserver sofaStreamObserver; + + private final Serializer serializer; + + private volatile Class returnType; + + public ClientStreamObserverAdapter(SofaStreamObserver sofaStreamObserver, byte serializeType) { + this.sofaStreamObserver = sofaStreamObserver; + this.serializer = SerializerFactory.getSerializer(serializeType); + } + + @Override + public void onNext(triple.Response response) { + byte[] responseData = response.getData().toByteArray(); + Object appResponse = null; + String returnTypeName = response.getType(); + if (responseData != null && responseData.length > 0) { + if (returnType == null && !returnTypeName.isEmpty()) { + try { + returnType = Class.forName(returnTypeName); + } catch (ClassNotFoundException e) { + throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Can not find return type :" + returnType); + } + } + appResponse = serializer.decode(new ByteArrayWrapperByteBuf(responseData), returnType, null); + } + + sofaStreamObserver.onNext(appResponse); + } + + @Override + public void onError(Throwable t) { + sofaStreamObserver.onError(t); + } + + @Override + public void onCompleted() { + sofaStreamObserver.onCompleted(); + } +} diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ResponseSerializeSofaStreamObserver.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ResponseSerializeSofaStreamObserver.java new file mode 100644 index 000000000..1889c561f --- /dev/null +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ResponseSerializeSofaStreamObserver.java @@ -0,0 +1,72 @@ +/* + * 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 com.alipay.sofa.rpc.message.triple.stream; + +import com.alipay.sofa.rpc.codec.Serializer; +import com.alipay.sofa.rpc.codec.SerializerFactory; +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; +import com.alipay.sofa.rpc.utils.TripleExceptionUtils; +import com.google.protobuf.ByteString; +import io.grpc.stub.StreamObserver; +import triple.Response; + +/** + * Response serialize stream handler. + */ +public class ResponseSerializeSofaStreamObserver implements SofaStreamObserver { + + private final StreamObserver streamObserver; + + private Serializer serializer; + + private String serializeType; + + public ResponseSerializeSofaStreamObserver(StreamObserver streamObserver, String serializeType) { + this.streamObserver = streamObserver; + if (StringUtils.isNotBlank(serializeType)) { + this.serializer = SerializerFactory.getSerializer(serializeType); + this.serializeType = serializeType; + } + } + + @Override + public void onNext(T message) { + Response.Builder builder = Response.newBuilder(); + builder.setType(message.getClass().getName()); + builder.setSerializeType(serializeType); + builder.setData(ByteString.copyFrom(serializer.encode(message, null).array())); + + streamObserver.onNext(builder.build()); + } + + @Override + public void onCompleted() { + streamObserver.onCompleted(); + } + + @Override + public void onError(Throwable throwable) { + streamObserver.onError(TripleExceptionUtils.asStatusRuntimeException(throwable)); + } + + public void setSerializeType(String serializeType) { + this.serializer = SerializerFactory.getSerializer(serializeType); + this.serializeType = serializeType; + } + +} diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java index dff254195..4b96e7cfb 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java @@ -18,6 +18,8 @@ import com.alipay.sofa.rpc.codec.Serializer; import com.alipay.sofa.rpc.codec.SerializerFactory; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.common.cache.ReflectCache; import com.alipay.sofa.rpc.common.utils.ClassTypeUtils; import com.alipay.sofa.rpc.common.utils.ClassUtils; import com.alipay.sofa.rpc.core.exception.RpcErrorType; @@ -27,8 +29,10 @@ import com.alipay.sofa.rpc.core.response.SofaResponse; import com.alipay.sofa.rpc.log.Logger; import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.message.triple.stream.ResponseSerializeSofaStreamObserver; import com.alipay.sofa.rpc.tracer.sofatracer.TracingContextKey; import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; import com.google.protobuf.ByteString; import com.google.protobuf.ProtocolStringList; import io.grpc.Context; @@ -57,28 +61,21 @@ public GenericServiceImpl(UniqueIdInvoker invoker) { @Override public void generic(Request request, StreamObserver responseObserver) { - ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); SofaRequest sofaRequest = TracingContextKey.getKeySofaRequest().get(Context.current()); String methodName = sofaRequest.getMethodName(); + Method declaredMethod = invoker.getDeclaredMethod(sofaRequest, request, RpcConstants.INVOKER_TYPE_UNARY); + if (declaredMethod == null) { + throw new SofaRpcException(RpcErrorType.SERVER_NOT_FOUND_INVOKER, "Cannot find invoke method " + + methodName); + } + try { ClassLoader serviceClassLoader = invoker.getServiceClassLoader(sofaRequest); Thread.currentThread().setContextClassLoader(serviceClassLoader); - - Method declaredMethod = invoker.getDeclaredMethod(sofaRequest, request); - if (declaredMethod == null) { - throw new SofaRpcException(RpcErrorType.SERVER_NOT_FOUND_INVOKER, "Cannot find invoke method " + - methodName); - } - Class[] argTypes = getArgTypes(request); Serializer serializer = SerializerFactory.getSerializer(request.getSerializeType()); - Object[] invokeArgs = getInvokeArgs(request, argTypes, serializer); - - // fill sofaRequest - sofaRequest.setMethod(declaredMethod); - sofaRequest.setMethodArgs(invokeArgs); - sofaRequest.setMethodArgSigs(ClassTypeUtils.getTypeStrs(argTypes, true)); + setUnaryOrServerRequestParams(sofaRequest, request, serializer, declaredMethod, false); SofaResponse response = invoker.invoke(sofaRequest); Object ret = getAppResponse(declaredMethod, response); @@ -98,6 +95,143 @@ public void generic(Request request, StreamObserver responseObserver) } } + @Override + public StreamObserver genericBiStream(StreamObserver responseObserver) { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + //通过上下文创建请求 + SofaRequest sofaRequest = TracingContextKey.getKeySofaRequest().get(Context.current()); + String uniqueName = invoker.getServiceUniqueName(sofaRequest); + Method serviceMethod = ReflectCache.getOverloadMethodCache(uniqueName, sofaRequest.getMethodName(), + new String[] { SofaStreamObserver.class.getCanonicalName() }); + + if (serviceMethod == null) { + throw new SofaRpcException(RpcErrorType.SERVER_NOT_FOUND_INVOKER, "Cannot find invoke method " + + sofaRequest.getMethodName()); + } + String methodName = serviceMethod.getName(); + try { + ClassLoader serviceClassLoader = invoker.getServiceClassLoader(sofaRequest); + Thread.currentThread().setContextClassLoader(serviceClassLoader); + ResponseSerializeSofaStreamObserver serverResponseHandler = new ResponseSerializeSofaStreamObserver( + responseObserver, + null); + + setBidirectionalStreamRequestParams(sofaRequest, serviceMethod, serverResponseHandler); + + SofaResponse sofaResponse = invoker.invoke(sofaRequest); + + SofaStreamObserver clientHandler = (SofaStreamObserver) sofaResponse.getAppResponse(); + + return new StreamObserver() { + private volatile Serializer serializer = null; + + private volatile String serializeType = null; + + private volatile Class[] argTypes = null; + + @Override + public void onNext(Request request) { + checkInitialize(request); + Object message = getInvokeArgs(request, argTypes, serializer, false)[0]; + serverResponseHandler.setSerializeType(serializeType); + clientHandler.onNext(message); + } + + @Override + public void onError(Throwable t) { + clientHandler.onError(t); + } + + @Override + public void onCompleted() { + clientHandler.onCompleted(); + } + + private void checkInitialize(Request request) { + if (serializer == null && argTypes == null) { + synchronized (this) { + if (serializer == null && argTypes == null) { + serializeType = request.getSerializeType(); + serializer = SerializerFactory.getSerializer(request.getSerializeType()); + argTypes = getArgTypes(request, false); + } + } + } + } + }; + } catch (Exception e) { + LOGGER.error("Invoke " + methodName + " error:", e); + throw new SofaRpcRuntimeException(e); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + @Override + public void genericServerStream(Request request, StreamObserver responseObserver) { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + SofaRequest sofaRequest = TracingContextKey.getKeySofaRequest().get(Context.current()); + Method serviceMethod = invoker.getDeclaredMethod(sofaRequest, request, RpcConstants.INVOKER_TYPE_SERVER_STREAMING); + + if (serviceMethod == null) { + throw new SofaRpcException(RpcErrorType.SERVER_NOT_FOUND_INVOKER, "Cannot find invoke method " + + sofaRequest.getMethodName()); + } + + String methodName = serviceMethod.getName(); + try { + ClassLoader serviceClassLoader = invoker.getServiceClassLoader(sofaRequest); + Thread.currentThread().setContextClassLoader(serviceClassLoader); + Serializer serializer = SerializerFactory.getSerializer(request.getSerializeType()); + + setUnaryOrServerRequestParams(sofaRequest, request, serializer, serviceMethod, true); + sofaRequest.getMethodArgs()[sofaRequest.getMethodArgs().length -1] = new ResponseSerializeSofaStreamObserver<>(responseObserver, request.getSerializeType()); + + invoker.invoke(sofaRequest); + } catch (Exception e) { + LOGGER.error("Invoke " + methodName + " error:", e); + throw new SofaRpcRuntimeException(e); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } + + /** + * Resolve method invoke args into request for unary or server-streaming calls. + * + * @param sofaRequest SofaRequest + * @param request Request + * @param serializer Serializer + * @param declaredMethod Target invoke method + */ + private void setUnaryOrServerRequestParams(SofaRequest sofaRequest, Request request, + Serializer serializer, Method declaredMethod, boolean isServerStreamCall) { + Class[] argTypes = getArgTypes(request, isServerStreamCall); + Object[] invokeArgs = getInvokeArgs(request, argTypes, serializer, isServerStreamCall); + + // fill sofaRequest + sofaRequest.setMethod(declaredMethod); + sofaRequest.setMethodArgs(invokeArgs); + sofaRequest.setMethodArgSigs(ClassTypeUtils.getTypeStrs(argTypes, true)); + } + + /** + * Resolve method invoke args into request for bidirectional stream calls. + * + * @param sofaRequest SofaRequest + * @param serviceMethod Target service method + * @param serverStreamPushHandler The StreamHandler used to push a message to a client. It's a wrapper for {@link StreamObserver}, and encode method return value to {@link Response}. + */ + private void setBidirectionalStreamRequestParams(SofaRequest sofaRequest, Method serviceMethod, + SofaStreamObserver serverStreamPushHandler) { + Class[] argTypes = new Class[] { SofaStreamObserver.class }; + Object[] invokeArgs = new Object[] { serverStreamPushHandler }; + + sofaRequest.setMethod(serviceMethod); + sofaRequest.setMethodArgs(invokeArgs); + sofaRequest.setMethodArgSigs(ClassTypeUtils.getTypeStrs(argTypes, true)); + } + private Object getAppResponse(Method method, SofaResponse response) { if (response.isError()) { throw new SofaRpcException(RpcErrorType.SERVER_UNDECLARED_ERROR, response.getErrorMsg()); @@ -113,21 +247,44 @@ private Object getAppResponse(Method method, SofaResponse response) { return ret; } - private Class[] getArgTypes(Request request) { + /** + * Get argument types from request. + * @param request original request + * @param addStreamHandler Whether add StreamHandler as the first method param. + *

+ * For server stream call, the StreamHandler won't be transported. + * To make the argument list conform to the method definition, we need to add it as first method param manually. + * + * @return param types of target method + */ + private Class[] getArgTypes(Request request, boolean addStreamHandler) { ProtocolStringList argTypesList = request.getArgTypesList(); - int size = argTypesList.size(); + + int size = addStreamHandler ? argTypesList.size() + 1 : argTypesList.size(); Class[] argTypes = new Class[size]; - for (int i = 0; i < size; i++) { + + for (int i = 0; i < argTypesList.size(); i++) { String typeName = argTypesList.get(i); argTypes[i] = ClassTypeUtils.getClass(typeName); } + + if (addStreamHandler) { + argTypes[size - 1] = SofaStreamObserver.class; + } return argTypes; } - private Object[] getInvokeArgs(Request request, Class[] argTypes, Serializer serializer) { + /** + * Get arguments from request. + * @param addStreamHandler if addStreamHandler == true, the first arg will be left blank and set later. + * + * @return params of target method. + */ + private Object[] getInvokeArgs(Request request, Class[] argTypes, Serializer serializer, boolean addStreamHandler) { List argsList = request.getArgsList(); - Object[] args = new Object[argsList.size()]; + int size = addStreamHandler ? argsList.size() + 1 : argsList.size(); + Object[] args = new Object[size]; for (int i = 0; i < argsList.size(); i++) { byte[] data = argsList.get(i).toByteArray(); args[i] = serializer.decode(new ByteArrayWrapperByteBuf(data), argTypes[i], diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java index f3f312cde..47f225352 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java @@ -40,7 +40,6 @@ import com.alipay.sofa.rpc.utils.SofaProtoUtils; import io.grpc.BindableService; import io.grpc.MethodDescriptor; -import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptors; import io.grpc.ServerMethodDefinition; import io.grpc.ServerServiceDefinition; @@ -58,7 +57,9 @@ import triple.Response; import java.lang.reflect.Method; + import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -328,11 +329,9 @@ private void setBindableProxiedImpl(ProviderConfig providerConfig, Invoker invok private ServerServiceDefinition buildSofaServiceDef(GenericServiceImpl genericService, ProviderConfig providerConfig) { ServerServiceDefinition templateDefinition = genericService.bindService(); - ServerCallHandler templateHandler = (ServerCallHandler) templateDefinition - .getMethods().iterator().next().getServerCallHandler(); List> methodDescriptor = getMethodDescriptor(providerConfig); - List> methodDefs = getMethodDefinitions(templateHandler, - methodDescriptor); + List> methodDefs = createMethodDefinition(templateDefinition,methodDescriptor); + // Bind the actual service to a specific method in the generic service ServerServiceDefinition.Builder builder = ServerServiceDefinition.builder(getServiceDescriptor( templateDefinition, providerConfig, methodDescriptor)); for (ServerMethodDefinition methodDef : methodDefs) { @@ -341,15 +340,27 @@ private ServerServiceDefinition buildSofaServiceDef(GenericServiceImpl genericSe return builder.build(); } - private List> getMethodDefinitions(ServerCallHandler templateHandler,List> methodDescriptors) { - List> result = new ArrayList<>(); - for (MethodDescriptor methodDescriptor : methodDescriptors) { - ServerMethodDefinition serverMethodDefinition = ServerMethodDefinition.create(methodDescriptor, templateHandler); - result.add(serverMethodDefinition); - } - return result; + private List> createMethodDefinition(ServerServiceDefinition geneticServiceDefinition, List> serviceMethods){ + Collection> genericServiceMethods = geneticServiceDefinition.getMethods(); + List> serverMethodDefinitions = new ArrayList<>(); + //Map ture service method to certain generic service method. + for (ServerMethodDefinition genericMethods : genericServiceMethods){ + for(MethodDescriptor methodDescriptor : serviceMethods){ + + if(methodDescriptor.getType().equals(genericMethods.getMethodDescriptor().getType())){ + + ServerMethodDefinition genericMeth = (ServerMethodDefinition) genericMethods; + + serverMethodDefinitions.add( + ServerMethodDefinition.create(methodDescriptor, genericMeth.getServerCallHandler()) + ); + } + } + } + return serverMethodDefinitions; } + private ServiceDescriptor getServiceDescriptor(ServerServiceDefinition template, ProviderConfig providerConfig, List> methodDescriptors) { String serviceName = providerConfig.getInterfaceId(); @@ -365,9 +376,11 @@ private ServiceDescriptor getServiceDescriptor(ServerServiceDefinition template, private List> getMethodDescriptor(ProviderConfig providerConfig) { List> result = new ArrayList<>(); Set methodNames = SofaProtoUtils.getMethodNames(providerConfig.getInterfaceId()); + Map streamCallTypeMap = SofaProtoUtils.cacheStreamCallType(providerConfig.getProxyClass()); for (String name : methodNames) { + MethodDescriptor.MethodType methodType = SofaProtoUtils.mapGrpcCallType(streamCallTypeMap.get(name)); MethodDescriptor methodDescriptor = MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) + .setType(methodType) .setFullMethodName(generateFullMethodName(providerConfig.getInterfaceId(), name)) .setSampledToLocalTracing(true) .setRequestMarshaller(ProtoUtils.marshaller( diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/UniqueIdInvoker.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/UniqueIdInvoker.java index 15b615bd3..7a9ce0669 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/UniqueIdInvoker.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/UniqueIdInvoker.java @@ -16,6 +16,7 @@ */ package com.alipay.sofa.rpc.server.triple; +import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.common.cache.ReflectCache; import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator; @@ -27,10 +28,13 @@ import com.alipay.sofa.rpc.core.response.SofaResponse; import com.alipay.sofa.rpc.invoke.Invoker; import com.alipay.sofa.rpc.server.ProviderProxyInvoker; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; import triple.Request; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -174,14 +178,19 @@ public ClassLoader getServiceClassLoader(SofaRequest sofaRequest) { return ReflectCache.getServiceClassLoader(uniqueName); } - public Method getDeclaredMethod(SofaRequest sofaRequest, Request request) { + public Method getDeclaredMethod(SofaRequest sofaRequest, Request request, String callType) { String uniqueName = this.getServiceUniqueName(sofaRequest); - return ReflectCache.getOverloadMethodCache(uniqueName, sofaRequest.getMethodName(), request - .getArgTypesList() - .toArray(new String[0])); + List argTypesList = request.getArgTypesList(); + if (RpcConstants.INVOKER_TYPE_SERVER_STREAMING.equals(callType)) { + List a = new ArrayList<>(argTypesList.size() + 1); + a.addAll(argTypesList); + a.add(SofaStreamObserver.class.getCanonicalName()); + argTypesList = a; + } + return ReflectCache.getOverloadMethodCache(uniqueName, sofaRequest.getMethodName(), argTypesList.toArray(new String[0])); } - private String getServiceUniqueName(SofaRequest sofaRequest) { + public String getServiceUniqueName(SofaRequest sofaRequest) { this.readLock.lock(); try { Invoker invoker = this.findInvoker(sofaRequest.getInterfaceName(), getUniqueIdFromInvokeContext()); diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java index 7079f3f13..af681155c 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java @@ -40,10 +40,14 @@ import com.alipay.sofa.rpc.log.LoggerFactory; import com.alipay.sofa.rpc.message.ResponseFuture; import com.alipay.sofa.rpc.message.triple.TripleResponseFuture; +import com.alipay.sofa.rpc.message.triple.stream.ClientStreamObserverAdapter; import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; -import com.google.protobuf.ByteString; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; +import com.alipay.sofa.rpc.utils.SofaProtoUtils; +import com.alipay.sofa.rpc.utils.TripleExceptionUtils; import io.grpc.CallOptions; import io.grpc.Channel; +import io.grpc.ClientCall; import io.grpc.MethodDescriptor; import io.grpc.Status; import io.grpc.protobuf.ProtoUtils; @@ -69,24 +73,30 @@ * @date 2018.12.15 7:06 PM */ public class TripleClientInvoker implements TripleInvoker { - private final static Logger LOGGER = LoggerFactory.getLogger(TripleClientInvoker.class); + private final static Logger LOGGER = LoggerFactory.getLogger(TripleClientInvoker.class); private final static String DEFAULT_SERIALIZATION = SERIALIZE_HESSIAN2; - protected Channel channel; + protected Channel channel; - protected ConsumerConfig consumerConfig; + protected ConsumerConfig consumerConfig; protected ProviderInfo providerInfo; - protected Method sofaStub; + protected Method sofaStub; - protected boolean useGeneric; + protected boolean useGeneric; - private Serializer serializer; - private String serialization; + private Serializer serializer; + private String serialization; - private Map methodMap = new ConcurrentHashMap<>(); + private final Map methodMap = new ConcurrentHashMap<>(); + + /** + * Method call type (Full method name - Streaming call type) + * Since gRPC does not support method overload, each method here will only represent a single call type. + */ + private Map methodCallType; public TripleClientInvoker(ConsumerConfig consumerConfig, ProviderInfo providerInfo, Channel channel) { this.channel = channel; @@ -101,8 +111,10 @@ public TripleClientInvoker(ConsumerConfig consumerConfig, ProviderInfo providerI try { sofaStub = enclosingClass.getDeclaredMethod("getSofaStub", Channel.class, CallOptions.class, int.class); } catch (NoSuchMethodException e) { - LOGGER.error("getSofaStub not found in enclosingClass" + enclosingClass.getName()); + LOGGER.error("getSofaStub not found in enclosingClass: {}", enclosingClass.getName()); } + } else { + methodCallType = SofaProtoUtils.cacheStreamCallType(consumerConfig.getProxyClass()); } } @@ -121,35 +133,127 @@ protected String getDefaultSerialization() { @Override public SofaResponse invoke(SofaRequest sofaRequest, int timeout) - throws Exception { + throws Exception { if (!useGeneric) { - SofaResponse sofaResponse = new SofaResponse(); - Object stub = sofaStub.invoke(null, channel, buildCustomCallOptions(sofaRequest, timeout), + return stubCall(sofaRequest, timeout); + } + + String streamType = methodCallType.get(sofaRequest.getMethod().getName()); + MethodDescriptor.MethodType callType = SofaProtoUtils.mapGrpcCallType(streamType); + switch (callType) { + case UNARY: + return genericUnaryCall(sofaRequest, timeout); + case BIDI_STREAMING: + return genericBinaryStreamCall(sofaRequest, timeout); + case CLIENT_STREAMING: + return genericClientStreamCall(sofaRequest, timeout); + case SERVER_STREAMING: + return genericServerStreamCall(sofaRequest, timeout); + default: + throw new SofaRpcException(RpcErrorType.CLIENT_CALL_TYPE, "Unknown stream call type:" + callType); + } + } + + private SofaResponse stubCall(SofaRequest sofaRequest, int timeout) throws Exception { + SofaResponse sofaResponse = new SofaResponse(); + Object stub = sofaStub.invoke(null, channel, buildCustomCallOptions(sofaRequest, timeout), timeout); - final Method method = sofaRequest.getMethod(); - Object appResponse = method.invoke(stub, sofaRequest.getMethodArgs()[0]); - sofaResponse.setAppResponse(appResponse); - return sofaResponse; - } else { - MethodDescriptor methodDescriptor = getMethodDescriptor(sofaRequest); - Request request = getRequest(sofaRequest, serialization, serializer); - Response response = (Response) ClientCalls.blockingUnaryCall(channel, methodDescriptor, + final Method method = sofaRequest.getMethod(); + Object appResponse = method.invoke(stub, sofaRequest.getMethodArgs()); + sofaResponse.setAppResponse(appResponse); + return sofaResponse; + } + + private SofaResponse genericUnaryCall(SofaRequest sofaRequest, int timeout) { + MethodDescriptor methodDescriptor = getMethodDescriptor(sofaRequest); + Request request = SofaProtoUtils.buildRequest(sofaRequest.getMethodArgSigs(), sofaRequest.getMethodArgs(), serialization, serializer, 0); + Response response = (Response) ClientCalls.blockingUnaryCall(channel, methodDescriptor, buildCustomCallOptions(sofaRequest, timeout), request); - SofaResponse sofaResponse = new SofaResponse(); - byte[] responseDate = response.getData().toByteArray(); - Class returnType = sofaRequest.getMethod().getReturnType(); - if (returnType != void.class) { - if (responseDate != null && responseDate.length > 0) { - Serializer responseSerializer = SerializerFactory.getSerializer(response.getSerializeType()); - Object appResponse = responseSerializer.decode(new ByteArrayWrapperByteBuf(responseDate), returnType, null); - sofaResponse.setAppResponse(appResponse); - } + SofaResponse sofaResponse = new SofaResponse(); + byte[] responseData = response.getData().toByteArray(); + Class returnType = sofaRequest.getMethod().getReturnType(); + if (returnType != void.class) { + if (responseData != null && responseData.length > 0) { + Serializer responseSerializer = SerializerFactory.getSerializer(response.getSerializeType()); + Object appResponse = responseSerializer.decode(new ByteArrayWrapperByteBuf(responseData), returnType, null); + sofaResponse.setAppResponse(appResponse); } - - return sofaResponse; } + return sofaResponse; + } + + private SofaResponse genericBinaryStreamCall(SofaRequest sofaRequest, int timeout) { + SofaStreamObserver sofaStreamObserver = (SofaStreamObserver) sofaRequest.getMethodArgs()[0]; + + MethodDescriptor methodDescriptor = getMethodDescriptor(sofaRequest); + ClientCall call = channel.newCall(methodDescriptor, buildCustomCallOptions(sofaRequest, timeout)); + + StreamObserver observer = ClientCalls.asyncBidiStreamingCall( + call, + new ClientStreamObserverAdapter( + sofaStreamObserver, + sofaRequest.getSerializeType() + ) + ); + SofaStreamObserver handler = new SofaStreamObserver() { + @Override + public void onNext(Object message) { + Object[] args = new Object[]{message}; + Request req = SofaProtoUtils.buildRequest(rebuildTrueRequestArgSigs(args), args, serialization, serializer, 0); + observer.onNext(req); + } + + @Override + public void onCompleted() { + observer.onCompleted(); + } + @Override + public void onError(Throwable throwable) { + observer.onError(TripleExceptionUtils.asStatusRuntimeException(throwable)); + } + }; + SofaResponse sofaResponse = new SofaResponse(); + sofaResponse.setAppResponse(handler); + return sofaResponse; + } + + private SofaResponse genericClientStreamCall(SofaRequest sofaRequest, int timeout) { + return genericBinaryStreamCall(sofaRequest, timeout); + } + + private SofaResponse genericServerStreamCall(SofaRequest sofaRequest, int timeout) { + SofaStreamObserver sofaStreamObserver = (SofaStreamObserver) sofaRequest.getMethodArgs()[sofaRequest.getMethodArgs().length - 1]; + + MethodDescriptor methodDescriptor = getMethodDescriptor(sofaRequest); + ClientCall call = channel.newCall(methodDescriptor, buildCustomCallOptions(sofaRequest, timeout)); + + Request req = SofaProtoUtils.buildRequest(sofaRequest.getMethodArgSigs(), sofaRequest.getMethodArgs(), serialization, serializer, 1); + + ClientStreamObserverAdapter responseObserver = new ClientStreamObserverAdapter(sofaStreamObserver, sofaRequest.getSerializeType()); + + ClientCalls.asyncServerStreamingCall(call, req, responseObserver); + + return new SofaResponse(); + } + + /** + * Build arg sigs for stream calls. + * + * @param requestArgs request args + * @return arg sigs, arg.getClass().getName(). + */ + private String[] rebuildTrueRequestArgSigs(Object[] requestArgs) { + String[] classes = new String[requestArgs.length]; + for (int k = 0; k < requestArgs.length; k++) { + if (requestArgs[k] != null) { + classes[k] = requestArgs[k].getClass().getName(); + } else { + classes[k] = void.class.getName(); + } + } + return classes; } @Override @@ -179,8 +283,7 @@ public ResponseFuture asyncInvoke(SofaRequest sofaRequest, int timeout) throws E } } } - Object stub = sofaStub.invoke(null, channel, buildCustomCallOptions(sofaRequest, timeout), - null, consumerConfig, timeout); + Object stub = sofaStub.invoke(null, channel, buildCustomCallOptions(sofaRequest, timeout), timeout); m.invoke(stub, sofaRequest.getMethodArgs()[0], new StreamObserver() { @Override public void onNext(Object o) { @@ -199,7 +302,7 @@ public void onCompleted() { }); } else { MethodDescriptor methodDescriptor = getMethodDescriptor(sofaRequest); - Request request = getRequest(sofaRequest, serialization, serializer); + Request request = SofaProtoUtils.buildRequest(sofaRequest.getMethodArgSigs(), sofaRequest.getMethodArgs(), serialization, serializer, 0); ClientCalls.asyncUnaryCall(channel.newCall(methodDescriptor, buildCustomCallOptions(sofaRequest, timeout)), request, new StreamObserver() { @Override public void onNext(Object o) { @@ -250,12 +353,12 @@ private void processSuccess(boolean needDecode, RpcInternalContext context, Sofa Object appResponse = o; if (needDecode) { Response response = (Response) o; - byte[] responseDate = response.getData().toByteArray(); + byte[] responseData = response.getData().toByteArray(); Class returnType = sofaRequest.getMethod().getReturnType(); if (returnType != void.class) { - if (responseDate != null && responseDate.length > 0) { + if (responseData != null && responseData.length > 0) { Serializer responseSerializer = SerializerFactory.getSerializer(response.getSerializeType()); - appResponse = responseSerializer.decode(new ByteArrayWrapperByteBuf(responseDate), returnType, null); + appResponse = responseSerializer.decode(new ByteArrayWrapperByteBuf(responseData), returnType, null); } } } @@ -299,7 +402,7 @@ private void processError(RpcInternalContext context, SofaRequest sofaRequest, T Status status = Status.fromThrowable(throwable); if (status.getCode() == Status.Code.UNKNOWN) { sofaResponseCallback.onAppException(throwable, sofaRequest.getMethodName(), sofaRequest); - }else { + } else { sofaResponseCallback.onSofaException(new SofaRpcException(RpcErrorType.UNKNOWN, status.getCause()), sofaRequest.getMethodName(), sofaRequest); } } else { @@ -342,41 +445,29 @@ protected void pickupBaggage(RpcInternalContext context, SofaResponse response) } } - private MethodDescriptor getMethodDescriptor(SofaRequest sofaRequest) { + private MethodDescriptor getMethodDescriptor(SofaRequest sofaRequest) { String serviceName = sofaRequest.getInterfaceName(); String methodName = sofaRequest.getMethodName(); MethodDescriptor.Marshaller requestMarshaller = ProtoUtils.marshaller(Request.getDefaultInstance()); MethodDescriptor.Marshaller responseMarshaller = ProtoUtils.marshaller(Response.getDefaultInstance()); String fullMethodName = generateFullMethodName(serviceName, methodName); - MethodDescriptor methodDescriptor = MethodDescriptor + + MethodDescriptor.Builder builder = MethodDescriptor .newBuilder() - .setType(MethodDescriptor.MethodType.UNARY) .setFullMethodName(fullMethodName) .setSampledToLocalTracing(true) .setRequestMarshaller((MethodDescriptor.Marshaller) requestMarshaller) - .setResponseMarshaller((MethodDescriptor.Marshaller) responseMarshaller) - .build(); - return methodDescriptor; - } - - public static Request getRequest(SofaRequest sofaRequest, String serialization, Serializer serializer) { - Request.Builder builder = Request.newBuilder(); - builder.setSerializeType(serialization); + .setResponseMarshaller((MethodDescriptor.Marshaller) responseMarshaller); - String[] methodArgSigs = sofaRequest.getMethodArgSigs(); - Object[] methodArgs = sofaRequest.getMethodArgs(); - - for (int i = 0; i < methodArgSigs.length; i++) { - Object arg = methodArgs[i]; - ByteString argByteString = ByteString.copyFrom(serializer.encode(arg, null).array()); - builder.addArgs(argByteString); - builder.addArgTypes(methodArgSigs[i]); - } + String streamType = methodCallType.get(sofaRequest.getMethod().getName()); + MethodDescriptor.MethodType callType = SofaProtoUtils.mapGrpcCallType(streamType); + builder.setType(callType); return builder.build(); } /** * set some custom info + * * @param sofaRequest * @param timeout * @return diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java index eec457315..780d7f5a8 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java @@ -16,15 +16,32 @@ */ package com.alipay.sofa.rpc.utils; +import com.alipay.sofa.rpc.codec.Serializer; +import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.common.utils.ClassUtils; +import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.core.exception.RpcErrorType; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; +import com.google.protobuf.ByteString; import io.grpc.BindableService; import io.grpc.CallOptions; import io.grpc.Channel; +import io.grpc.MethodDescriptor; +import triple.Request; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.HashSet; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alipay.sofa.rpc.common.RpcConstants.INVOKER_TYPE_BI_STREAMING; +import static com.alipay.sofa.rpc.common.RpcConstants.INVOKER_TYPE_CLIENT_STREAMING; +import static com.alipay.sofa.rpc.common.RpcConstants.INVOKER_TYPE_SERVER_STREAMING; /** * @author zhaowang @@ -62,4 +79,71 @@ public static boolean checkIfUseGeneric(ConsumerConfig consumerConfig) { return true; } + public static MethodDescriptor.MethodType mapGrpcCallType(String callType) { + return Optional.ofNullable(callType).map(type -> { + switch (type) { + case INVOKER_TYPE_BI_STREAMING: + return MethodDescriptor.MethodType.BIDI_STREAMING; + case INVOKER_TYPE_CLIENT_STREAMING: + return MethodDescriptor.MethodType.CLIENT_STREAMING; + case INVOKER_TYPE_SERVER_STREAMING: + return MethodDescriptor.MethodType.SERVER_STREAMING; + default: + throw new SofaRpcException(RpcErrorType.CLIENT_CALL_TYPE, "Unsupported invoke type:" + callType); + } + }).orElse(MethodDescriptor.MethodType.UNARY); + } + + public static Map cacheStreamCallType(Class proxyClass) { + Map methodCallType = new ConcurrentHashMap<>(); + Method[] declaredMethods = proxyClass.getDeclaredMethods(); + for (Method method : declaredMethods) { + String streamType = mapStreamType(method); + if (StringUtils.isNotBlank(streamType)) { + methodCallType.put(method.getName(), streamType); + } + } + return methodCallType; + } + + /** + * Gets the stream call type of certain method + * + * @param method the method + * @return call type,server/client/bidirectional stream or default value. If not mapped to any stream call type, use the default value + */ + private static String mapStreamType(Method method) { + Class[] paramClasses = method.getParameterTypes(); + Class returnClass = method.getReturnType(); + + int paramLen = paramClasses.length; + + //BidirectionalStream & ClientStream + if (paramLen > 0 && SofaStreamObserver.class.isAssignableFrom(paramClasses[0]) && SofaStreamObserver.class.isAssignableFrom(returnClass)) { + if (paramLen > 1) { + throw new SofaRpcException(RpcErrorType.CLIENT_CALL_TYPE, "Bidirectional/Client stream method parameters can be only one StreamHandler."); + } + return RpcConstants.INVOKER_TYPE_BI_STREAMING; + } + //ServerStream + else if (paramLen > 1 && SofaStreamObserver.class.isAssignableFrom(paramClasses[paramLen -1]) && void.class == returnClass) { + return RpcConstants.INVOKER_TYPE_SERVER_STREAMING; + } else if (SofaStreamObserver.class.isAssignableFrom(returnClass) || Arrays.stream(paramClasses).anyMatch(SofaStreamObserver.class::isAssignableFrom)) { + throw new SofaRpcException(RpcErrorType.CLIENT_CALL_TYPE, "SofaStreamObserver can only at the specified location of parameter.Please check related docs."); + } + return null; + } + + public static Request buildRequest(String[] methodArgSigs, Object[] methodArgs, String serialization, + Serializer serializer, int backOffset) { + Request.Builder builder = Request.newBuilder(); + builder.setSerializeType(serialization); + for (int i = 0; i < methodArgSigs.length - backOffset; i++) { + Object arg = methodArgs[i]; + ByteString argByteString = ByteString.copyFrom(serializer.encode(arg, null).array()); + builder.addArgs(argByteString); + builder.addArgTypes(methodArgSigs[i]); + } + return builder.build(); + } } \ No newline at end of file diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java new file mode 100644 index 000000000..5387e3af3 --- /dev/null +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java @@ -0,0 +1,32 @@ +/* + * 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 com.alipay.sofa.rpc.utils; + +import io.grpc.Status; +import io.grpc.StatusRuntimeException; + +public class TripleExceptionUtils { + + public static StatusRuntimeException asStatusRuntimeException(Throwable t) { + if (t != null) { + return Status.fromThrowable(t).withDescription(t.getMessage()).withCause(t.getCause()).asRuntimeException(); + } else { + return Status.UNKNOWN.withDescription("Error message is null.").asRuntimeException(); + } + } + +} diff --git a/remoting/remoting-triple/src/main/proto/transformer.proto b/remoting/remoting-triple/src/main/proto/transformer.proto index be08b097d..2152268db 100644 --- a/remoting/remoting-triple/src/main/proto/transformer.proto +++ b/remoting/remoting-triple/src/main/proto/transformer.proto @@ -9,6 +9,11 @@ option java_outer_classname = "GenericProto"; service GenericService { rpc generic (Request) returns (Response) {} + + rpc genericBiStream (stream Request) returns (stream Response){} + + rpc genericServerStream(Request) returns (stream Response){} + } message Request { diff --git a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/server/triple/GenericServiceImplTest.java b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/server/triple/GenericServiceImplTest.java index e0c566ec3..bfc366958 100644 --- a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/server/triple/GenericServiceImplTest.java +++ b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/server/triple/GenericServiceImplTest.java @@ -27,7 +27,7 @@ import com.alipay.sofa.rpc.server.ProviderProxyInvoker; import com.alipay.sofa.rpc.tracer.sofatracer.TracingContextKey; import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; -import com.alipay.sofa.rpc.transport.triple.TripleClientInvoker; +import com.alipay.sofa.rpc.utils.SofaProtoUtils; import io.grpc.Context; import org.junit.Assert; import org.junit.Test; @@ -136,7 +136,8 @@ private Object getReturnValue(Method method) { private Request buildRequest(Method method, Object[] args) { Class[] parameterTypes = method.getParameterTypes(); SofaRequest sofaRequest = MessageBuilder.buildSofaRequest(HelloService.class, method, parameterTypes, args); - Request request = TripleClientInvoker.getRequest(sofaRequest, serialization, serializer); + Request request = SofaProtoUtils.buildRequest(sofaRequest.getMethodArgSigs(), sofaRequest.getMethodArgs(), + serialization, serializer, 0); Context context = Context.current().withValue(TracingContextKey.getKeySofaRequest(), sofaRequest); context.attach(); return request; diff --git a/test/test-integration/src/main/proto/helloworld.proto b/test/test-integration/src/main/proto/helloworld.proto index a237b8e2f..0b8c94f14 100644 --- a/test/test-integration/src/main/proto/helloworld.proto +++ b/test/test-integration/src/main/proto/helloworld.proto @@ -25,6 +25,12 @@ package helloworld; service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} + + rpc SayHelloBinary (stream HelloRequest) returns (stream HelloReply){} + + rpc SayHelloClientStream (stream HelloRequest) returns (HelloReply){} + + rpc SayHelloServerStream (HelloRequest) returns (stream HelloReply){} } // The request message containing the user's name. diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/GreeterImpl.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/GreeterImpl.java index ec3e2f334..a16e5be06 100644 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/GreeterImpl.java +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/GreeterImpl.java @@ -16,6 +16,8 @@ */ package com.alipay.sofa.rpc.test.triple; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; import io.grpc.examples.helloworld.SofaGreeterTriple; @@ -23,13 +25,18 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; public class GreeterImpl extends SofaGreeterTriple.GreeterImplBase { + private static final Logger LOGGER = LoggerFactory.getLogger(GreeterImpl.class); + //Intentionally using unsupported format - static final DateTimeFormatter[] datetimeFormatter = new DateTimeFormatter[] { DateTimeFormatter.ISO_DATE_TIME, - DateTimeFormatter.ISO_LOCAL_DATE_TIME, - DateTimeFormatter.BASIC_ISO_DATE }; + private static final DateTimeFormatter[] datetimeFormatter = new DateTimeFormatter[] { + DateTimeFormatter.ISO_DATE_TIME, + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + DateTimeFormatter.BASIC_ISO_DATE }; @Override public void sayHello(HelloRequest req, StreamObserver responseObserver) { @@ -51,4 +58,67 @@ public void sayHello(HelloRequest req, StreamObserver responseObserv responseObserver.onNext(reply); responseObserver.onCompleted(); } + + @Override + public StreamObserver sayHelloBinary(StreamObserver responseObserver) { + return new StreamObserver() { + + @Override + public void onNext(HelloRequest value) { + LOGGER.info("bi stream req onNext"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(value.getName()) + .build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(value.getName()) + .build()); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("bi stream req onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("bi stream req onCompleted"); + responseObserver.onCompleted(); + } + }; + } + + @Override + public StreamObserver sayHelloClientStream(StreamObserver responseObserver) { + + List helloRequestList = new ArrayList<>(); + + return new StreamObserver() { + + @Override + public void onNext(HelloRequest value) { + LOGGER.info("client stream req receive"); + helloRequestList.add(value); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("client stream req onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("client stream req completed"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(helloRequestList.get(0).getName() + helloRequestList.size()) + .build()); + responseObserver.onCompleted(); + } + }; + } + + @Override + public void sayHelloServerStream(HelloRequest request, StreamObserver responseObserver) { + LOGGER.info("server stream req receive"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 1).build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 2).build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 3).build()); + responseObserver.onCompleted(); + } } \ No newline at end of file diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/NativeGrpcGreeterImpl.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/NativeGrpcGreeterImpl.java new file mode 100644 index 000000000..ddb839718 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/NativeGrpcGreeterImpl.java @@ -0,0 +1,127 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple; + +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.StreamObserver; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Even + * @date 2024/5/9 10:21 + */ +public class NativeGrpcGreeterImpl extends GreeterGrpc.GreeterImplBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(NativeGrpcGreeterImpl.class); + + //Intentionally using unsupported format + private static final DateTimeFormatter[] datetimeFormatter = new DateTimeFormatter[] { + DateTimeFormatter.ISO_DATE_TIME, + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + DateTimeFormatter.BASIC_ISO_DATE }; + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloRequest.DateTime reqDateTime = req.getDateTime(); + int i = 0; + try { + i = Integer.parseInt(reqDateTime.getTime()); + } catch (Exception e) { + //TODO: handle exception + } + LocalDateTime dt = LocalDateTime.now(); + String dtStr = dt.format(datetimeFormatter[i % datetimeFormatter.length]); + HelloRequest.DateTime rplyDateTime = HelloRequest.DateTime.newBuilder(reqDateTime) + .setDate(dtStr).build(); + HelloReply reply = HelloReply.newBuilder() + .setMessage("Hello " + req.getName()) + .setDateTime(rplyDateTime) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + + @Override + public StreamObserver sayHelloBinary(StreamObserver responseObserver) { + return new StreamObserver() { + + @Override + public void onNext(HelloRequest value) { + LOGGER.info("bi stream req onNext"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(value.getName()) + .build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(value.getName()) + .build()); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("bi stream req onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("bi stream req onCompleted"); + responseObserver.onCompleted(); + } + }; + } + + @Override + public StreamObserver sayHelloClientStream(StreamObserver responseObserver) { + List helloRequestList = new ArrayList<>(); + + return new StreamObserver() { + + @Override + public void onNext(HelloRequest value) { + LOGGER.info("client stream req receive"); + helloRequestList.add(value); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("client stream req onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("client stream req completed"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(helloRequestList.get(0).getName() + helloRequestList.size()) + .build()); + responseObserver.onCompleted(); + } + }; + } + + @Override + public void sayHelloServerStream(HelloRequest request, StreamObserver responseObserver) { + LOGGER.info("server stream req receive"); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 1).build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 2).build()); + responseObserver.onNext(HelloReply.newBuilder().setMessage(request.getName() + 3).build()); + responseObserver.onCompleted(); + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ClientRequest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ClientRequest.java new file mode 100644 index 000000000..9da046c09 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ClientRequest.java @@ -0,0 +1,36 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +public class ClientRequest { + private String msg; + + private int count; + + public ClientRequest(String msg, int count) { + this.msg = msg; + this.count = count; + } + + public String getMsg() { + return msg; + } + + public int getCount() { + return count; + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendClientRequest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendClientRequest.java new file mode 100644 index 000000000..cd5adee15 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendClientRequest.java @@ -0,0 +1,39 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +/** + * @author Even + * @date 2024/4/15 10:33 + */ +public class ExtendClientRequest extends ClientRequest { + + private String extendString; + + public ExtendClientRequest(String msg, int count, String extendString) { + super(msg, count); + this.extendString = extendString; + } + + public String getExtendString() { + return extendString; + } + + public void setExtendString(String extendString) { + this.extendString = extendString; + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendServerResponse.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendServerResponse.java new file mode 100644 index 000000000..9037680da --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ExtendServerResponse.java @@ -0,0 +1,39 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +/** + * @author Even + * @date 2024/4/15 10:33 + */ +public class ExtendServerResponse extends ServerResponse { + + private String extendString; + + public ExtendServerResponse(String msg, int count, String extendString) { + super(msg, count); + this.extendString = extendString; + } + + public String getExtendString() { + return extendString; + } + + public void setExtendString(String extendString) { + this.extendString = extendString; + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java new file mode 100644 index 000000000..b66d34a46 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java @@ -0,0 +1,32 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +import com.alipay.sofa.rpc.transport.SofaStreamObserver; + +public interface HelloService { + + String CMD_TRIGGER_STREAM_FINISH = "finish"; + + String CMD_TRIGGER_STREAM_ERROR = "error"; + + String ERROR_MSG = "error msg"; + + SofaStreamObserver sayHelloBiStream(SofaStreamObserver sofaStreamObserver); + + void sayHelloServerStream(ClientRequest clientRequest, SofaStreamObserver sofaStreamObserver); +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java new file mode 100644 index 000000000..3d40fc350 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java @@ -0,0 +1,81 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; + +public class HelloServiceImpl implements HelloService { + + private static final Logger LOGGER = LoggerFactory.getLogger(HelloServiceImpl.class); + + @Override + public SofaStreamObserver sayHelloBiStream(SofaStreamObserver sofaStreamObserver) { + return new SofaStreamObserver() { + + @Override + public void onNext(ClientRequest clientRequest) { + LOGGER.info("bi stream req onMessage"); + if (clientRequest.getMsg().equals(CMD_TRIGGER_STREAM_FINISH)) { + sofaStreamObserver.onCompleted(); + } else if (clientRequest.getMsg().equals(CMD_TRIGGER_STREAM_ERROR)) { + sofaStreamObserver.onError(new RuntimeException(ERROR_MSG)); + } else { + if (clientRequest instanceof ExtendClientRequest) { + sofaStreamObserver.onNext(new ExtendServerResponse(clientRequest.getMsg(), clientRequest + .getCount(), ((ExtendClientRequest) clientRequest).getExtendString())); + } else { + sofaStreamObserver.onNext(new ServerResponse(clientRequest.getMsg(), clientRequest.getCount())); + } + } + } + + @Override + public void onCompleted() { + LOGGER.info("bi stream req onFinish"); + sofaStreamObserver.onCompleted(); + } + + @Override + public void onError(Throwable throwable) { + LOGGER.error("bi stream req onException", throwable); + sofaStreamObserver.onNext(new ServerResponse("Received exception:" + throwable.getMessage(), -2)); + sofaStreamObserver.onError(throwable); + } + }; + } + + @Override + public void sayHelloServerStream(ClientRequest clientRequest, SofaStreamObserver sofaStreamObserver) { + LOGGER.info("server stream req receive"); + sofaStreamObserver.onNext(new ServerResponse(clientRequest.getMsg(), clientRequest.getCount())); + sofaStreamObserver.onNext(new ExtendServerResponse(clientRequest.getMsg(), clientRequest.getCount() + 1, + "extendString")); + sofaStreamObserver.onNext(new ServerResponse(clientRequest.getMsg(), clientRequest.getCount() + 2)); + sofaStreamObserver.onNext(new ExtendServerResponse(clientRequest.getMsg(), clientRequest.getCount() + 3, + "extendString")); + sofaStreamObserver.onNext(new ServerResponse(clientRequest.getMsg(), clientRequest.getCount() + 4)); + if (clientRequest.getMsg().equals(CMD_TRIGGER_STREAM_ERROR)) { + sofaStreamObserver.onError(new RuntimeException(ERROR_MSG)); + sofaStreamObserver.onCompleted(); + } else { + sofaStreamObserver.onCompleted(); + } + } + +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ServerResponse.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ServerResponse.java new file mode 100644 index 000000000..3d7ec3878 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ServerResponse.java @@ -0,0 +1,36 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +public class ServerResponse { + private String msg; + + private int count; + + public ServerResponse(String msg, int count) { + this.msg = msg; + this.count = count; + } + + public String getMsg() { + return msg; + } + + public int getCount() { + return count; + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java new file mode 100644 index 000000000..bf145e502 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java @@ -0,0 +1,224 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.context.RpcInternalContext; +import com.alipay.sofa.rpc.context.RpcInvokeContext; +import com.alipay.sofa.rpc.context.RpcRunningState; +import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.transport.SofaStreamObserver; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class TripleGenericStreamTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(TripleGenericStreamTest.class); + private static final String HELLO_MSG = "Hello, world!"; + private static ConsumerConfig consumerConfig; + private static ProviderConfig providerConfig; + private static HelloService helloServiceInst; + private static HelloService helloServiceRef; + + @BeforeClass + public static void beforeClass() throws InterruptedException { + RpcRunningState.setUnitTestMode(true); + ServerConfig serverConfig = new ServerConfig() + .setProtocol("tri") + .setPort(50066) + .setDaemon(false); + + helloServiceInst = Mockito.spy(new HelloServiceImpl()); + providerConfig = new ProviderConfig() + .setInterfaceId(HelloService.class.getName()) + .setRef(helloServiceInst) + .setServer(serverConfig); + providerConfig.export(); + + consumerConfig = new ConsumerConfig() + .setInterfaceId(HelloService.class.getName()) + .setProtocol("tri") + .setDirectUrl("triple://127.0.0.1:50066"); + helloServiceRef = consumerConfig.refer(); + } + + @AfterClass + public static void afterClass() { + consumerConfig.unRefer(); + providerConfig.unExport(); + RpcRuntimeContext.destroy(); + RpcInternalContext.removeContext(); + RpcInvokeContext.removeContext(); + } + + @Test + public void testTripleBiStreamFinish() throws InterruptedException { + testTripleBiStream(false); + } + + @Test + public void testTripleBiStreamException() throws InterruptedException { + testTripleBiStream(true); + } + + public void testTripleBiStream(boolean endWithException) throws InterruptedException { + int requestTimes = 5; + CountDownLatch countDownLatch = new CountDownLatch(requestTimes + 1); + + AtomicBoolean receivedFinish = new AtomicBoolean(false); + AtomicBoolean receivedException = new AtomicBoolean(false); + + List serverResponseList = new ArrayList<>(); + SofaStreamObserver sofaStreamObserver = helloServiceRef + .sayHelloBiStream(new SofaStreamObserver() { + final AtomicInteger requestCount = new AtomicInteger(0); + + @Override + public void onNext(ServerResponse message) { + LOGGER.info("bi stream resp onMessage"); + Assert.assertEquals(requestCount.getAndIncrement(), message.getCount()); + Assert.assertEquals(HELLO_MSG, message.getMsg()); + serverResponseList.add(message); + countDownLatch.countDown(); + } + + @Override + public void onCompleted() { + LOGGER.info("bi stream resp onFinish"); + receivedFinish.set(true); + countDownLatch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + LOGGER.error("bi stream resp onException", throwable); + Assert.assertTrue(throwable.getMessage().contains(HelloService.ERROR_MSG)); + receivedException.set(true); + countDownLatch.countDown(); + } + }); + + for (int k = 0; k < requestTimes; k++) { + if (k % 2 == 0) { + sofaStreamObserver.onNext(new ClientRequest(HELLO_MSG, k)); + } else { + sofaStreamObserver.onNext(new ExtendClientRequest(HELLO_MSG, k, "testExtendString")); + } + } + if (!endWithException) { + sofaStreamObserver.onNext(new ClientRequest(HelloService.CMD_TRIGGER_STREAM_FINISH, -2)); + Assert.assertTrue(countDownLatch.await(20, TimeUnit.SECONDS)); + Assert.assertTrue(receivedFinish.get()); + sofaStreamObserver.onCompleted(); + assertServerResponseType(serverResponseList); + Assert.assertFalse(receivedException.get()); + Assert.assertThrows(Throwable.class, () -> sofaStreamObserver.onNext(new ClientRequest("", 123))); + } else { + sofaStreamObserver.onNext(new ClientRequest(HelloService.CMD_TRIGGER_STREAM_ERROR, -2)); + Assert.assertTrue(countDownLatch.await(20, TimeUnit.SECONDS)); + sofaStreamObserver.onError(new RuntimeException(HelloService.ERROR_MSG)); + Assert.assertThrows(Throwable.class, () -> sofaStreamObserver.onNext(new ClientRequest(HELLO_MSG, 0))); + Assert.assertFalse(receivedFinish.get()); + Assert.assertTrue(receivedException.get()); + } + verify(helloServiceInst, times(1)).sayHelloBiStream(any()); + } + + @Test + public void testTripleServerStreamFinish() throws InterruptedException { + testTripleServerStream(false); + } + + @Test + public void testTripleServerStreamException() throws InterruptedException { + testTripleServerStream(true); + } + + public void testTripleServerStream(boolean endWithException) throws InterruptedException { + reset(helloServiceInst); + AtomicInteger count = new AtomicInteger(0); + int responseTimes = 5; + CountDownLatch countDownLatch = new CountDownLatch(responseTimes + 1); + AtomicBoolean responseFinished = new AtomicBoolean(false); + AtomicBoolean responseException = new AtomicBoolean(false); + + List serverResponseList = new ArrayList<>(); + helloServiceRef.sayHelloServerStream(new ClientRequest(endWithException ? HelloService.CMD_TRIGGER_STREAM_ERROR : HELLO_MSG, 0), new SofaStreamObserver() { + @Override + public void onNext(ServerResponse message) { + Assert.assertEquals(endWithException ? HelloService.CMD_TRIGGER_STREAM_ERROR : HELLO_MSG, + message.getMsg()); + Assert.assertEquals(count.getAndIncrement(), message.getCount()); + serverResponseList.add(message); + countDownLatch.countDown(); + } + + @Override + public void onCompleted() { + responseFinished.set(true); + countDownLatch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + Assert.assertTrue(throwable.getMessage().contains(HelloService.ERROR_MSG)); + responseException.set(true); + countDownLatch.countDown(); + } + }); + + Assert.assertTrue(countDownLatch.await(20, TimeUnit.SECONDS)); + if (endWithException) { + Assert.assertTrue(responseException.get()); + Assert.assertFalse(responseFinished.get()); + assertServerResponseType(serverResponseList); + } else { + Assert.assertTrue(responseFinished.get()); + Assert.assertFalse(responseException.get()); + } + Assert.assertEquals(responseTimes, count.get()); + verify(helloServiceInst, times(1)).sayHelloServerStream(any(), any()); + } + + private void assertServerResponseType(List serverResponseList) { + for (int i = 0; i < serverResponseList.size(); i++) { + if (i % 2 != 0) { + Assert.assertTrue(serverResponseList.get(i) instanceof ExtendServerResponse); + } + } + } + +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleStubStreamTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleStubStreamTest.java new file mode 100644 index 000000000..cae0b87b7 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleStubStreamTest.java @@ -0,0 +1,413 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.config.ApplicationConfig; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.ServerConfig; +import com.alipay.sofa.rpc.context.RpcInternalContext; +import com.alipay.sofa.rpc.context.RpcInvokeContext; +import com.alipay.sofa.rpc.context.RpcRunningState; +import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.test.triple.GreeterImpl; +import com.alipay.sofa.rpc.test.triple.NativeGrpcGreeterImpl; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.SofaGreeterTriple; +import io.grpc.stub.StreamObserver; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @author Even + * @date 2024/4/10 14:45 + */ +public class TripleStubStreamTest { + + private static final Logger LOGGER = LoggerFactory + .getLogger(TripleStubStreamTest.class); + + private static ConsumerConfig consumerConfig; + private static ProviderConfig providerConfig; + private static SofaGreeterTriple.IGreeter greeterStub; + + private static GreeterGrpc.GreeterBlockingStub nativeBlockingStub; + private static GreeterGrpc.GreeterStub nativeAsyncStub; + + private static ConsumerConfig consumerConfigToNative; + private static SofaGreeterTriple.IGreeter greeterStubToNative; + + @BeforeClass + public static void beforeClass() throws InterruptedException, IOException { + RpcRunningState.setUnitTestMode(true); + ApplicationConfig applicationConfig = new ApplicationConfig().setAppName("triple-server"); + int port = 50052; + ServerConfig serverConfig = new ServerConfig() + .setProtocol(RpcConstants.PROTOCOL_TYPE_TRIPLE) + .setPort(port); + + providerConfig = new ProviderConfig() + .setApplication(applicationConfig) + .setBootstrap(RpcConstants.PROTOCOL_TYPE_TRIPLE) + .setInterfaceId(SofaGreeterTriple.IGreeter.class.getName()) + .setRef(new GreeterImpl()) + .setServer(serverConfig); + providerConfig.export(); + + consumerConfig = new ConsumerConfig<>(); + consumerConfig.setInterfaceId(SofaGreeterTriple.IGreeter.class.getName()) + .setProtocol(RpcConstants.PROTOCOL_TYPE_TRIPLE) + .setDirectUrl("tri://127.0.0.1:" + port); + + greeterStub = consumerConfig.refer(); + + ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1", 50052).usePlaintext() + .build(); + nativeBlockingStub = GreeterGrpc.newBlockingStub(channel); + nativeAsyncStub = GreeterGrpc.newStub(channel); + + Server server = ServerBuilder.forPort(50051) + .addService(new NativeGrpcGreeterImpl()) + .build(); + server.start(); + + consumerConfigToNative = new ConsumerConfig<>(); + consumerConfigToNative.setInterfaceId(SofaGreeterTriple.IGreeter.class.getName()) + .setProtocol(RpcConstants.PROTOCOL_TYPE_TRIPLE) + .setDirectUrl("tri://127.0.0.1:" + 50051); + greeterStubToNative = consumerConfigToNative.refer(); + Thread.sleep(10000); + } + + @AfterClass + public static void afterClass() { + consumerConfig.unRefer(); + providerConfig.unExport(); + consumerConfigToNative.unRefer(); + RpcRuntimeContext.destroy(); + RpcInternalContext.removeContext(); + RpcInvokeContext.removeContext(); + } + + @Test + public void testTripleStubBiStream() throws InterruptedException { + HelloRequest request = HelloRequest.newBuilder().setName("Hello world!").build(); + CountDownLatch biCountDownLatch = new CountDownLatch(5); + StreamObserver requestStreamObserver = greeterStub + .sayHelloBinary(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + Assert.assertEquals(value.getMessage(), request.getName()); + LOGGER.info("bi stream resp onNext"); + biCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.error("bi stream resp error", t); + } + + @Override + public void onCompleted() { + LOGGER.info("bi stream resp onCompleted"); + biCountDownLatch.countDown(); + } + }); + requestStreamObserver.onNext(request); + requestStreamObserver.onNext(request); + requestStreamObserver.onCompleted(); + Assert.assertTrue(biCountDownLatch.await(10, TimeUnit.SECONDS)); + + } + + @Test + public void testTripleStubClientStream() throws InterruptedException { + HelloRequest request = HelloRequest.newBuilder().setName("Hello world!").build(); + CountDownLatch clientStreamCountDownLatch = new CountDownLatch(2); + StreamObserver helloRequestStreamObserver = greeterStub + .sayHelloClientStream(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + LOGGER.info("client stream resp onCompleted"); + Assert.assertEquals(value.getMessage(), request.getName() + 2); + clientStreamCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.error("client stream resp error", t); + } + + @Override + public void onCompleted() { + clientStreamCountDownLatch.countDown(); + LOGGER.info("client stream resp onCompleted"); + } + }); + + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onCompleted(); + Assert.assertTrue(clientStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + } + + @Test + public void testTripleStubServerStream() throws InterruptedException { + HelloRequest request = HelloRequest.newBuilder().setName("Hello world!").build(); + CountDownLatch blockServerStreamCountDownLatch = new CountDownLatch(3); + Iterator helloReplyIterator = greeterStub.sayHelloServerStream(request); + int i = 0; + while (helloReplyIterator.hasNext()) { + i++; + blockServerStreamCountDownLatch.countDown(); + Assert.assertEquals(helloReplyIterator.next().getMessage(), request.getName() + i); + } + Assert.assertTrue(blockServerStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + + CountDownLatch serverStreamCountDownLatch = new CountDownLatch(3); + greeterStub.sayHelloServerStream(request, new StreamObserver() { + + int i = 0; + + @Override + public void onNext(HelloReply value) { + LOGGER.info("server stream resp onNext"); + i++; + serverStreamCountDownLatch.countDown(); + Assert.assertEquals(value.getMessage(), request.getName() + i); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("server stream resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("server stream resp onCompleted"); + } + }); + Assert.assertTrue(serverStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + } + + @Test + public void testGrpcClientToTripleServer() throws InterruptedException { + // UNARY + HelloRequest request = HelloRequest.newBuilder().setName("world!").build(); + Assert.assertEquals("Hello world!", nativeBlockingStub.sayHello(request).getMessage()); + + // BIDI_STREAMING + CountDownLatch biCountDownLatch = new CountDownLatch(5); + StreamObserver helloRequestStreamObserver = nativeAsyncStub + .sayHelloBinary(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + Assert.assertEquals(value.getMessage(), request.getName()); + LOGGER.info("nativeAsyncStub sayHelloBinary resp onNext"); + biCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("nativeAsyncStub sayHelloBinary resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("nativeAsyncStub sayHelloBinary resp onCompleted"); + biCountDownLatch.countDown(); + } + }); + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onCompleted(); + Assert.assertTrue(biCountDownLatch.await(10, TimeUnit.SECONDS)); + + // CLIENT_STREAMING + CountDownLatch clientStreamCountDownLatch = new CountDownLatch(2); + StreamObserver clientStreamObserver = nativeAsyncStub + .sayHelloClientStream(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + LOGGER.info("nativeAsyncStub sayHelloClientStream resp onNext"); + Assert.assertEquals(value.getMessage(), request.getName() + 2); + clientStreamCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("nativeAsyncStub sayHelloClientStream resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("nativeAsyncStub sayHelloClientStream resp onCompleted"); + clientStreamCountDownLatch.countDown(); + } + }); + clientStreamObserver.onNext(request); + clientStreamObserver.onNext(request); + clientStreamObserver.onCompleted(); + Assert.assertTrue(clientStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + + // SERVER_STREAMING + CountDownLatch serverStreamCountDownLatch = new CountDownLatch(3); + Iterator helloReplyIterator = nativeBlockingStub.sayHelloServerStream(request); + int i = 0; + while (helloReplyIterator.hasNext()) { + i++; + serverStreamCountDownLatch.countDown(); + Assert.assertEquals(helloReplyIterator.next().getMessage(), request.getName() + i); + } + Assert.assertTrue(serverStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + + CountDownLatch serverAsyncStreamCountDownLatch = new CountDownLatch(4); + nativeAsyncStub.sayHelloServerStream(request, new StreamObserver() { + @Override + public void onNext(HelloReply value) { + LOGGER.info("nativeAsyncStub sayHelloServerStream resp onNext"); + serverAsyncStreamCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("nativeAsyncStub sayHelloServerStream resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("nativeAsyncStub sayHelloServerStream resp onCompleted"); + serverAsyncStreamCountDownLatch.countDown(); + } + }); + Assert.assertTrue(serverAsyncStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + } + + @Test + public void testTripleClientToGrpcServer() throws InterruptedException { + // UNARY + HelloRequest request = HelloRequest.newBuilder().setName("world!").build(); + Assert.assertEquals("Hello world!", greeterStubToNative.sayHello(request).getMessage()); + + // BIDI_STREAMING + CountDownLatch biCountDownLatch = new CountDownLatch(5); + StreamObserver helloRequestStreamObserver = greeterStubToNative + .sayHelloBinary(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + Assert.assertEquals(value.getMessage(), request.getName()); + LOGGER.info("greeterStubToNative sayHelloBinary resp onNext"); + biCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("greeterStubToNative sayHelloBinary resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("greeterStubToNative sayHelloBinary resp onCompleted"); + biCountDownLatch.countDown(); + } + }); + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onNext(request); + helloRequestStreamObserver.onCompleted(); + Assert.assertTrue(biCountDownLatch.await(10, TimeUnit.SECONDS)); + + // CLIENT_STREAMING + CountDownLatch clientStreamCountDownLatch = new CountDownLatch(2); + StreamObserver clientStreamObserver = greeterStubToNative + .sayHelloClientStream(new StreamObserver() { + @Override + public void onNext(HelloReply value) { + LOGGER.info("greeterStubToNative sayHelloClientStream resp onNext"); + Assert.assertEquals(value.getMessage(), request.getName() + 2); + clientStreamCountDownLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("greeterStubToNative sayHelloServerStream resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("greeterStubToNative sayHelloClientStream resp onCompleted"); + clientStreamCountDownLatch.countDown(); + } + }); + clientStreamObserver.onNext(request); + clientStreamObserver.onNext(request); + clientStreamObserver.onCompleted(); + Assert.assertTrue(clientStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + + // SERVER_STREAMING + CountDownLatch blockServerStreamCountDownLatch = new CountDownLatch(3); + Iterator helloReplyIterator = greeterStubToNative.sayHelloServerStream(request); + int i = 0; + while (helloReplyIterator.hasNext()) { + i++; + blockServerStreamCountDownLatch.countDown(); + Assert.assertEquals(helloReplyIterator.next().getMessage(), request.getName() + i); + } + Assert.assertTrue(blockServerStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + + CountDownLatch serverStreamCountDownLatch = new CountDownLatch(3); + greeterStubToNative.sayHelloServerStream(request, new StreamObserver() { + + int i = 0; + + @Override + public void onNext(HelloReply value) { + LOGGER.info("server stream resp onNext"); + i++; + serverStreamCountDownLatch.countDown(); + Assert.assertEquals(value.getMessage(), request.getName() + i); + } + + @Override + public void onError(Throwable t) { + LOGGER.info("server stream resp onError"); + } + + @Override + public void onCompleted() { + LOGGER.info("server stream resp onCompleted"); + } + }); + Assert.assertTrue(serverStreamCountDownLatch.await(10, TimeUnit.SECONDS)); + } + +} From 21acf2823ee5ab998e0b79d7481d2315292433a3 Mon Sep 17 00:00:00 2001 From: Wang Chengming <634749869@qq.com> Date: Tue, 14 May 2024 10:37:55 +0800 Subject: [PATCH 37/64] Optimize performance for h2c protocol (#1400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * optimize performance for h2c protocol * optimize performance for h2c protocol --------- Co-authored-by: 呈铭 --- .../sofa/rpc/common/BatchExecutorQueue.java | 119 ++++++++++++++++++ .../rpc/common/BatchExecutorQueueTest.java | 88 +++++++++++++ .../transport/netty/NettyBatchWriteQueue.java | 76 +++++++++++ .../rpc/transport/netty/NettyChannel.java | 32 +++-- .../netty/NettyBatchWriteQueueTest.java | 88 +++++++++++++ .../rpc/transport/netty/NettyChannelTest.java | 87 +++++++++++++ 6 files changed, 479 insertions(+), 11 deletions(-) create mode 100644 core/common/src/main/java/com/alipay/sofa/rpc/common/BatchExecutorQueue.java create mode 100644 core/common/src/test/java/com/alipay/sofa/rpc/common/BatchExecutorQueueTest.java create mode 100644 remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueue.java create mode 100644 remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java create mode 100644 remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/BatchExecutorQueue.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/BatchExecutorQueue.java new file mode 100644 index 000000000..d8bdcd458 --- /dev/null +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/BatchExecutorQueue.java @@ -0,0 +1,119 @@ +/* + * 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 com.alipay.sofa.rpc.common; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 批量执行队列 + * + * @author chengming + * @version BatchExecutorQueue.java, v 0.1 2024年02月28日 5:36 PM chengming + */ +public class BatchExecutorQueue { + + static final int DEFAULT_QUEUE_SIZE = 128; + + private final Queue queue; + + private final AtomicBoolean scheduled; + + private final int chunkSize; + + public BatchExecutorQueue() { + this(DEFAULT_QUEUE_SIZE); + } + + public BatchExecutorQueue(int chunkSize) { + this.queue = new ConcurrentLinkedQueue<>(); + this.scheduled = new AtomicBoolean(false); + this.chunkSize = chunkSize; + } + + public void enqueue(T message, Executor executor) { + queue.add(message); + scheduleFlush(executor); + } + + protected void scheduleFlush(Executor executor) { + if (scheduled.compareAndSet(false, true)) { + executor.execute(() -> this.run(executor)); + } + } + + void run(Executor executor) { + try { + Queue snapshot = new LinkedList<>(); + T item; + while ((item = queue.poll()) != null) { + snapshot.add(item); + } + int i = 0; + boolean flushedOnce = false; + while ((item = snapshot.poll()) != null) { + if (snapshot.size() == 0) { + flushedOnce = false; + break; + } + if (i == chunkSize) { + i = 0; + flush(item); + flushedOnce = true; + } else { + prepare(item); + i++; + } + } + if ((i != 0 || !flushedOnce) && item != null) { + flush(item); + } + } finally { + scheduled.set(false); + if (!queue.isEmpty()) { + scheduleFlush(executor); + } + } + } + + protected void prepare(T item) { + } + + protected void flush(T item) { + } + + /** + * UT only + * @return + */ + @Deprecated + public AtomicBoolean getScheduled() { + return scheduled; + } + + /** + * UT only + * @return + */ + @Deprecated + public Queue getQueue() { + return queue; + } +} \ No newline at end of file diff --git a/core/common/src/test/java/com/alipay/sofa/rpc/common/BatchExecutorQueueTest.java b/core/common/src/test/java/com/alipay/sofa/rpc/common/BatchExecutorQueueTest.java new file mode 100644 index 000000000..d77b08b3b --- /dev/null +++ b/core/common/src/test/java/com/alipay/sofa/rpc/common/BatchExecutorQueueTest.java @@ -0,0 +1,88 @@ +/* + * 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 com.alipay.sofa.rpc.common; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +/** + * @author chengming + * @version BatchExecutorQueueTest.java, v 0.1 2024年03月01日 10:55 AM chengming + */ +public class BatchExecutorQueueTest { + + private BatchExecutorQueue batchExecutorQueue; + + @Mock + private Executor mockExecutor; + + @Captor + private ArgumentCaptor runnableCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + batchExecutorQueue = spy(new BatchExecutorQueue<>(2)); + } + + @Test + public void testEnqueueAndRun() { + Object message1 = new Object(); + Object message2 = new Object(); + Object message3 = new Object(); + + // 测试 enqueue 方法以及是否通过 executor 调度了 run 方法 + batchExecutorQueue.enqueue(message1, mockExecutor); + batchExecutorQueue.enqueue(message2, mockExecutor); + batchExecutorQueue.enqueue(message3, mockExecutor); + + verify(mockExecutor, atLeastOnce()).execute(runnableCaptor.capture()); + + Runnable scheduledRunnable = runnableCaptor.getValue(); + Assert.assertNotNull(scheduledRunnable); + scheduledRunnable.run(); + + // 验证队列是否为空 + Assert.assertTrue(batchExecutorQueue.getQueue().isEmpty()); + } + + @Test + public void testScheduleFlush() { + AtomicBoolean scheduled = batchExecutorQueue.getScheduled(); + Assert.assertFalse(scheduled.get()); + + batchExecutorQueue.scheduleFlush(mockExecutor); + Assert.assertTrue(scheduled.get()); + + // 验证是否有任务提交到 executor + verify(mockExecutor).execute(any(Runnable.class)); + } + +} diff --git a/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueue.java b/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueue.java new file mode 100644 index 000000000..2ad3dbd1a --- /dev/null +++ b/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueue.java @@ -0,0 +1,76 @@ +/* + * 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 com.alipay.sofa.rpc.transport.netty; + +import com.alipay.sofa.rpc.common.BatchExecutorQueue; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPromise; +import io.netty.channel.EventLoop; + +/** + * @author chengming + * @version NettyBatchWriteQueue.java, v 0.1 2024年02月28日 5:42 PM chengming + */ +public class NettyBatchWriteQueue extends BatchExecutorQueue { + + private final Channel channel; + + private final EventLoop eventLoop; + + private NettyBatchWriteQueue(Channel channel) { + this.channel = channel; + this.eventLoop = channel.eventLoop(); + } + + public ChannelFuture enqueue(Object message) { + return enqueue(message, channel.newPromise()); + } + + public ChannelFuture enqueue(Object message, ChannelPromise channelPromise) { + MessageTuple messageTuple = new MessageTuple(message, channelPromise); + super.enqueue(messageTuple, eventLoop); + return messageTuple.channelPromise; + } + + @Override + protected void prepare(MessageTuple item) { + channel.write(item.originMessage, item.channelPromise); + } + + @Override + protected void flush(MessageTuple item) { + prepare(item); + channel.flush(); + } + + public static NettyBatchWriteQueue createWriteQueue(Channel channel) { + return new NettyBatchWriteQueue(channel); + } + + static class MessageTuple { + + private final Object originMessage; + + private final ChannelPromise channelPromise; + + public MessageTuple(Object originMessage, ChannelPromise channelPromise) { + this.originMessage = originMessage; + this.channelPromise = channelPromise; + } + } +} diff --git a/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyChannel.java b/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyChannel.java index 4b71a9ccb..590bfde39 100644 --- a/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyChannel.java +++ b/remoting/remoting-http/src/main/java/com/alipay/sofa/rpc/transport/netty/NettyChannel.java @@ -48,8 +48,11 @@ public class NettyChannel extends AbstractChannel { + if (!future1.isSuccess()) { + Throwable throwable = future1.cause(); + LOGGER.error("Failed to send to " + + NetUtils.channelToString(localAddress(), remoteAddress()) + + " for msg : " + obj + + ", Cause by:", throwable); } }); } @@ -98,4 +98,14 @@ public void operationComplete(Future future1) throws Exception { public boolean isAvailable() { return channel.isOpen() && channel.isActive(); } + + /** + * UT only + * @param writeQueue + */ + @Deprecated + public void setWriteQueue(NettyBatchWriteQueue writeQueue) { + this.writeQueue = writeQueue; + } + } diff --git a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java new file mode 100644 index 000000000..446544cfc --- /dev/null +++ b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java @@ -0,0 +1,88 @@ +/* + * 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 com.alipay.sofa.rpc.transport.netty; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPromise; +import io.netty.channel.EventLoop; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * @author chengming + * @version NettyBatchWriteQueueTest.java, v 0.1 2024年03月01日 11:06 AM chengming + */ +public class NettyBatchWriteQueueTest { + + @Mock + private Channel mockChannel; + + @Mock + private EventLoop mockEventLoop; + + @Mock + private ChannelPromise mockChannelPromise; + + private NettyBatchWriteQueue nettyBatchWriteQueue; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mockChannel.eventLoop()).thenReturn(mockEventLoop); + when(mockChannel.newPromise()).thenReturn(mockChannelPromise); + nettyBatchWriteQueue = NettyBatchWriteQueue.createWriteQueue(mockChannel); + } + + @Test + public void testEnqueue() { + Object message = new Object(); + ChannelFuture future = nettyBatchWriteQueue.enqueue(message); + Assert.assertNotNull(future); + + Mockito.verify(mockEventLoop).execute(any(Runnable.class)); + } + + @Test + public void testPrepare() { + Object message = new Object(); + NettyBatchWriteQueue.MessageTuple messageTuple = new NettyBatchWriteQueue.MessageTuple(message, + mockChannelPromise); + nettyBatchWriteQueue.prepare(messageTuple); + + Mockito.verify(mockChannel).write(eq(message), eq(mockChannelPromise)); + } + + @Test + public void testFlush() { + Object message = new Object(); + NettyBatchWriteQueue.MessageTuple messageTuple = new NettyBatchWriteQueue.MessageTuple(message, + mockChannelPromise); + nettyBatchWriteQueue.flush(messageTuple); + + Mockito.verify(mockChannel).write(eq(message), eq(mockChannelPromise)); + Mockito.verify(mockChannel).flush(); + } +} \ No newline at end of file diff --git a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java new file mode 100644 index 000000000..e5be4aec6 --- /dev/null +++ b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java @@ -0,0 +1,87 @@ +/* + * 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 com.alipay.sofa.rpc.transport.netty; + +import com.alipay.sofa.rpc.common.utils.NetUtils; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.EventLoop; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; + +import java.net.InetSocketAddress; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +/** + * @author chengming + * @version NettyChannelTest.java, v 0.1 2024年02月29日 3:18 PM chengming + */ +public class NettyChannelTest { + + @Mock + private Channel mockChannel = Mockito.mock(Channel.class); + + @Mock + private ChannelHandlerContext mockContext = Mockito.mock(ChannelHandlerContext.class); + + @Mock + private NettyBatchWriteQueue mockWriteQueue = Mockito.mock(NettyBatchWriteQueue.class); + + @Mock + private ChannelFuture mockFuture = Mockito.mock(ChannelFuture.class); + + private NettyChannel nettyChannel; + + @Before + public void setUp() { + Mockito.when(mockChannel.eventLoop()).thenReturn(Mockito.mock(EventLoop.class)); + Mockito.when(mockChannel.alloc()).thenReturn(PooledByteBufAllocator.DEFAULT); + when(mockContext.channel()).thenReturn(mockChannel); + when(mockWriteQueue.enqueue(any())).thenReturn(mockFuture); + nettyChannel = new NettyChannel(mockChannel); + nettyChannel.setWriteQueue(mockWriteQueue); + } + + @Test + public void testRunSuccess() throws Exception { + nettyChannel.writeAndFlush("111"); + + Mockito.verify(mockWriteQueue).enqueue("111"); + + ArgumentCaptor captor = ArgumentCaptor.forClass(GenericFutureListener.class); + Mockito.verify(mockFuture).addListener(captor.capture()); + + // 模拟 FutureListener 的回调 + GenericFutureListener> listener = captor.getValue(); + listener.operationComplete((Future) mockFuture); + + // 验证没有错误日志被记录(因为操作是成功的) + Mockito.verify(Mockito.mock(NetUtils.class), times(10)); + NetUtils.channelToString(any(InetSocketAddress.class), any(InetSocketAddress.class)); + } + +} From d6d5c85caa12ab41dbce73785bf7c4a071eea300 Mon Sep 17 00:00:00 2001 From: evenliu Date: Thu, 16 May 2024 18:00:40 +0800 Subject: [PATCH 38/64] support default filter config (#1415) Co-authored-by: liujianjun.ljj --- .../com/alipay/sofa/rpc/common/RpcOptions.java | 4 ++++ .../rpc/config/AbstractInterfaceConfig.java | 17 ++++++++++++++++- .../alipay/sofa/rpc/filter/FilterChainTest.java | 3 --- .../std/config/AbstractInterfaceConfigTest.java | 11 ++++++++++- .../src/test/resources/sofa-rpc/rpc-config.json | 3 ++- .../sofa/rpc/common/rpc-config-default.json | 2 ++ 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java index c083625cc..ed8ade316 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java @@ -122,6 +122,10 @@ public class RpcOptions { * 默认Tracer实现 */ public static final String DEFAULT_TRACER = "default.tracer"; + /** + * 默认filter实现 + */ + public static final String DEFAULT_FILTERS = "default.filters"; /** * 注册中心发现服务(保存注册中心地址的服务)的地址 diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java index 336292369..acc4a74e1 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java @@ -42,7 +42,9 @@ import java.util.concurrent.ConcurrentHashMap; import static com.alipay.sofa.rpc.common.RpcConfigs.getBooleanValue; +import static com.alipay.sofa.rpc.common.RpcConfigs.getListValue; import static com.alipay.sofa.rpc.common.RpcConfigs.getStringValue; +import static com.alipay.sofa.rpc.common.RpcOptions.DEFAULT_FILTERS; import static com.alipay.sofa.rpc.common.RpcOptions.DEFAULT_GROUP; import static com.alipay.sofa.rpc.common.RpcOptions.DEFAULT_PROXY; import static com.alipay.sofa.rpc.common.RpcOptions.DEFAULT_SERIALIZATION; @@ -106,7 +108,8 @@ public abstract class AbstractInterfaceConfig filter; + protected List filter = new ArrayList( + getListValue(DEFAULT_FILTERS)); /** * 注册中心配置,可配置多个 @@ -361,6 +364,18 @@ public S setFilter(List filter) { return castThis(); } + /** + * add filter + * + * @param filter the add filter + */ + public void addFilter(List filter) { + if(this.filter == null) { + filter = new ArrayList<>(); + } + this.filter.addAll(filter); + } + /** * Gets registry. * diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/filter/FilterChainTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/filter/FilterChainTest.java index 2b6984b85..647ce4c34 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/filter/FilterChainTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/filter/FilterChainTest.java @@ -25,7 +25,6 @@ import org.junit.Test; import java.util.ArrayList; -import java.util.Arrays; /** * @@ -38,12 +37,10 @@ public class FilterChainTest { public void buildProviderChain() { ProviderConfig providerConfig = new ProviderConfig(); - providerConfig.setFilter(Arrays.asList("testChainFilter0", "-testChainFilter8")); providerConfig.setInterfaceId(Serializer.class.getName()); ConsumerConfig consumerConfig = new ConsumerConfig(); ArrayList list = new ArrayList(); - consumerConfig.setFilter(Arrays.asList("testChainFilter0", "-testChainFilter8")); list.add(new TestChainFilter1()); list.add(new TestChainFilter2()); list.add(new TestChainFilter3()); diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java index fa25d4bc3..f04724e24 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java @@ -58,7 +58,7 @@ public void testDefaultValue() { assertEquals(null, defaultConfig.getInterfaceId()); assertEquals("", defaultConfig.getUniqueId()); assertEquals(null, defaultConfig.getFilterRef()); - assertEquals(null, defaultConfig.getFilter()); + assertNotNull(defaultConfig.getFilter()); assertEquals(null, defaultConfig.getRegistry()); assertEquals(null, defaultConfig.getMethods()); assertEquals("hessian2", defaultConfig.getSerialization()); @@ -122,9 +122,18 @@ public void testSetGet() { config.setFilterRef(filterRefList); assertSame(filterRefList, config.getFilterRef()); + List defaultFilter = config.getFilter(); List filterList = new ArrayList<>(); + filterList.add("testFilter"); + config.addFilter(filterList); + Assert.assertTrue(defaultFilter.contains("testChainFilter0")); + Assert.assertTrue(defaultFilter.contains("-testChainFilter8")); + Assert.assertTrue(defaultFilter.contains("testFilter")); + assertSame(defaultFilter, config.getFilter()); + config.setFilter(filterList); assertSame(filterList, config.getFilter()); + assertNotSame(defaultFilter, config.getFilter()); List registryConfigs = new ArrayList<>(); config.setRegistry(registryConfigs); diff --git a/core/api/src/test/resources/sofa-rpc/rpc-config.json b/core/api/src/test/resources/sofa-rpc/rpc-config.json index 56d8da171..6eee71f61 100644 --- a/core/api/src/test/resources/sofa-rpc/rpc-config.json +++ b/core/api/src/test/resources/sofa-rpc/rpc-config.json @@ -1,4 +1,5 @@ { "rpc.config.order": 999, - "logger.impl": "com.alipay.sofa.rpc.log.SystemLogger" + "logger.impl": "com.alipay.sofa.rpc.log.SystemLogger", + "default.filters" :["testChainFilter0", "-testChainFilter8"] } \ No newline at end of file diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json index 6ad8f836f..50895ffae 100644 --- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json +++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json @@ -66,6 +66,8 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支 "default.transport": "netty4", // 默认tracer实现 "default.tracer": "", + // 默认filter实现 + "default.filters": [], /*-------------默认配置值结束-------------*/ From c7a45ea4132ae72daef30450f5b0b2d1f6a61fba Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 17 May 2024 16:21:38 +0800 Subject: [PATCH 39/64] support consumer routers config (#1416) * support consumer routers config * support consumer routers config --------- Co-authored-by: liujianjun.ljj --- .../alipay/sofa/rpc/client/RouterChain.java | 5 ++--- .../alipay/sofa/rpc/common/RpcOptions.java | 7 +++++++ .../sofa/rpc/config/ConsumerConfig.java | 18 ++++++++++++++++- .../alipay/sofa/rpc/filter/FilterChain.java | 4 ++-- .../sofa/rpc/client/RouterChainTest.java | 1 - .../rpc/std/config/ConsumerConfigTest.java | 20 ++++++++++++++++++- .../test/resources/sofa-rpc/rpc-config.json | 3 ++- .../sofa/rpc/common/rpc-config-default.json | 1 + 8 files changed, 50 insertions(+), 9 deletions(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/client/RouterChain.java b/core/api/src/main/java/com/alipay/sofa/rpc/client/RouterChain.java index 41eeb5a69..e841d99ab 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/client/RouterChain.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/client/RouterChain.java @@ -143,7 +143,7 @@ public static RouterChain buildConsumerChain(ConsumerBootstrap consumerBootstrap List> extensionRouters = new ArrayList>(); List routerAliases = consumerConfig.getRouter(); if (CommonUtils.isNotEmpty(routerAliases)) { - for (String routerAlias : routerAliases) { + routerAliases.stream().distinct().forEach(routerAlias -> { if (startsWithExcludePrefix(routerAlias)) { // 排除用的特殊字符 excludes.add(routerAlias.substring(1)); } else { @@ -152,7 +152,7 @@ public static RouterChain buildConsumerChain(ConsumerBootstrap consumerBootstrap extensionRouters.add(extensionRouter); } } - } + }); } // 解析自动加载的router if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) { // 配了-*和-default表示不加载内置 @@ -162,7 +162,6 @@ public static RouterChain buildConsumerChain(ConsumerBootstrap consumerBootstrap } } } - excludes = null; // 不需要了 // 按order从小到大排序 if (extensionRouters.size() > 1) { extensionRouters.sort(Comparator.comparingInt(ExtensionClass::getOrder)); diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java index ed8ade316..46c43206c 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java @@ -380,6 +380,13 @@ public class RpcOptions { */ public static final String CONSUMER_REJECTED_EXECUTION_POLICY = "consumer.rejected.execution.policy"; + /** + * 需要解析的 routers + * + * @since 5.13.0 + */ + public static final String CONSUMER_ROUTERS = "consumer.routers"; + /** * 默认回调线程池最小 */ diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java index 1b72bc901..031a9316a 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java @@ -33,10 +33,12 @@ import java.io.Serializable; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.List; import static com.alipay.sofa.rpc.common.RpcConfigs.getBooleanValue; import static com.alipay.sofa.rpc.common.RpcConfigs.getIntValue; +import static com.alipay.sofa.rpc.common.RpcConfigs.getListValue; import static com.alipay.sofa.rpc.common.RpcConfigs.getStringValue; import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_REJECTED_EXECUTION_POLICY; import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_ADDRESS_HOLDER; @@ -56,6 +58,7 @@ import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_RECONNECT_PERIOD; import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_REPEATED_REFERENCE_LIMIT; import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_RETRIES; +import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_ROUTERS; import static com.alipay.sofa.rpc.common.RpcOptions.CONSUMER_STICKY; import static com.alipay.sofa.rpc.common.RpcOptions.DEFAULT_PROTOCOL; @@ -173,7 +176,8 @@ public class ConsumerConfig extends AbstractInterfaceConfig router; + protected List router = new ArrayList( + getListValue(CONSUMER_ROUTERS)); /** * 路由规则引用,多个用英文逗号隔开。List @@ -682,6 +686,18 @@ public ConsumerConfig setRouter(List router) { return this; } + /** + * Add router. + * + * @param router the add router + */ + public void addRouter(List router) { + if (this.router == null) { + this.router = new ArrayList<>(); + } + this.router.addAll(router); + } + /** * Gets routerRef. * diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/filter/FilterChain.java b/core/api/src/main/java/com/alipay/sofa/rpc/filter/FilterChain.java index 9b0e97c20..e8488751c 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/filter/FilterChain.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/filter/FilterChain.java @@ -193,7 +193,7 @@ private static List selectActualFilters(AbstractInterfaceConfig config, List> extensionFilters = new LinkedList>(); List filterAliases = config.getFilter(); // if (CommonUtils.isNotEmpty(filterAliases)) { - for (String filterAlias : filterAliases) { + filterAliases.stream().distinct().forEach(filterAlias -> { if (startsWithExcludePrefix(filterAlias)) { // 排除用的特殊字符 excludes.add(filterAlias.substring(1)); } else { @@ -202,7 +202,7 @@ private static List selectActualFilters(AbstractInterfaceConfig config, extensionFilters.add(filter); } } - } + }); } // 解析自动加载的过滤器 if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) { // 配了-*和-default表示不加载内置 diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/client/RouterChainTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/client/RouterChainTest.java index 17e436777..b762e4d23 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/client/RouterChainTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/client/RouterChainTest.java @@ -48,7 +48,6 @@ public void buildProviderChain() { ConsumerConfig config = new ConsumerConfig(); config.setBootstrap("test"); ArrayList list = new ArrayList(); - config.setRouter(Arrays.asList("testChainRouter0", "-testChainRouter8", "notExistChainRouter")); list.add(new TestChainRouter1()); list.add(new TestChainRouter2()); list.add(new TestChainRouter3()); diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/ConsumerConfigTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/ConsumerConfigTest.java index fabb40a41..43d5daa0d 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/ConsumerConfigTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/ConsumerConfigTest.java @@ -24,9 +24,13 @@ import com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException; import com.alipay.sofa.rpc.std.sample.SampleService; import com.alipay.sofa.rpc.std.sample.SampleServiceImpl; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; + /** * @author zhaowang * @version : ConsumerConfigTest.java, v 0.1 2022年01月28日 2:33 下午 zhaowang @@ -59,7 +63,7 @@ public void testDefaultValue() { assertEquals(30000, config.getHeartbeatPeriod()); assertEquals(10000, config.getReconnectPeriod()); assertEquals("DISCARD", config.getRejectedExecutionPolicy()); - assertEquals(null, config.getRouter()); + assertNotNull(config.getRouter()); assertEquals(null, config.getRouterRef()); assertEquals(null, config.getOnReturn()); assertEquals(null, config.getOnConnect()); @@ -119,6 +123,20 @@ public void testGetInterfaceId() { assertEquals("serviceName", config.getInterfaceId()); } + @Test + public void testRouter() { + List router = config.getRouter(); + List addRouter = new ArrayList<>(); + addRouter.add("testRouter"); + config.addRouter(addRouter); + assertSame(router, config.getRouter()); + Assert.assertTrue(router.contains("testRouter")); + + config.setRouter(addRouter); + assertNotSame(router, config.getRouter()); + assertSame(addRouter, config.getRouter()); + } + public interface InnerInterface { } diff --git a/core/api/src/test/resources/sofa-rpc/rpc-config.json b/core/api/src/test/resources/sofa-rpc/rpc-config.json index 6eee71f61..fa1fc161b 100644 --- a/core/api/src/test/resources/sofa-rpc/rpc-config.json +++ b/core/api/src/test/resources/sofa-rpc/rpc-config.json @@ -1,5 +1,6 @@ { "rpc.config.order": 999, "logger.impl": "com.alipay.sofa.rpc.log.SystemLogger", - "default.filters" :["testChainFilter0", "-testChainFilter8"] + "default.filters" : ["testChainFilter0", "-testChainFilter8", "testChainFilter0"], + "consumer.routers" : ["testChainRouter0", "-testChainRouter8", "notExistChainRouter", "testChainRouter0"] } \ No newline at end of file diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json index 50895ffae..796594c8f 100644 --- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json +++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json @@ -213,6 +213,7 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支 "consumer.connect.create.when.absent": true, // 默认回调线程池满时的拒绝策略,可用值:DISCARD, CALLER_RUNS, CALLER_HANDLE_EXCEPTION "consumer.rejected.execution.policy": "DISCARD", + "consumer.routers": [], /*-------------Consumer相关配置结束-------------*/ From 6b5f63966c490224bc0b55b8d4a9de3a1274aed9 Mon Sep 17 00:00:00 2001 From: evenliu Date: Wed, 22 May 2024 14:23:06 +0800 Subject: [PATCH 40/64] add providerProcessRegister event and record context to bolt (#1417) Co-authored-by: liujianjun.ljj --- all/pom.xml | 4 +- bom/pom.xml | 4 +- .../bootstrap/DefaultProviderBootstrap.java | 9 ++++ .../rpc/context/RecordContextResolver.java | 43 ++++++++++++++++++ .../event/ProviderProcessorRegisterEvent.java | 44 +++++++++++++++++++ .../ProviderProcessorUnRegistryEvent.java | 44 +++++++++++++++++++ .../rpc/server/bolt/BoltServerProcessor.java | 2 + 7 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/context/RecordContextResolver.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorRegisterEvent.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorUnRegistryEvent.java diff --git a/all/pom.xml b/all/pom.xml index 271a754f1..0fc29d63f 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -56,12 +56,12 @@ 1.8 utf-8 1.7.21 - 1.3.15 + 1.4.0 3.29.2-GA 4.1.44.Final 3.5.3 3.6.3.Final - 1.6.6 + 1.6.10 3.0.8 1.4.1 1.9.8 diff --git a/bom/pom.xml b/bom/pom.xml index 4ce1bd589..3826b3c47 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -53,8 +53,8 @@ 4.13.1 - 1.6.6 - 1.3.15 + 1.6.10 + 1.4.0 3.0.8 1.4.1 diff --git a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultProviderBootstrap.java b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultProviderBootstrap.java index e7e46737b..0d7cff051 100644 --- a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultProviderBootstrap.java +++ b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultProviderBootstrap.java @@ -26,6 +26,9 @@ import com.alipay.sofa.rpc.config.ServerConfig; import com.alipay.sofa.rpc.context.RpcRuntimeContext; import com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException; +import com.alipay.sofa.rpc.event.EventBus; +import com.alipay.sofa.rpc.event.ProviderProcessorRegisterEvent; +import com.alipay.sofa.rpc.event.ProviderProcessorUnRegistryEvent; import com.alipay.sofa.rpc.ext.Extension; import com.alipay.sofa.rpc.invoke.Invoker; import com.alipay.sofa.rpc.listener.ConfigListener; @@ -175,6 +178,9 @@ private void doExport() { Server server = serverConfig.buildIfAbsent(); // 注册请求调用器 server.registerProcessor(providerConfig, providerProxyInvoker); + if (EventBus.isEnable(ProviderProcessorRegisterEvent.class)) { + EventBus.post(new ProviderProcessorRegisterEvent(providerConfig, serverConfig)); + } if (serverConfig.isAutoStart()) { server.start(); } @@ -306,6 +312,9 @@ public void unExport() { if (server != null) { try { server.unRegisterProcessor(providerConfig, serverConfig.isAutoStart()); + if (EventBus.isEnable(ProviderProcessorUnRegistryEvent.class)) { + EventBus.post(new ProviderProcessorUnRegistryEvent(providerConfig, serverConfig)); + } } catch (Exception e) { if (LOGGER.isWarnEnabled(appName)) { // TODO WARN diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/context/RecordContextResolver.java b/core/api/src/main/java/com/alipay/sofa/rpc/context/RecordContextResolver.java new file mode 100644 index 000000000..479f29d68 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/context/RecordContextResolver.java @@ -0,0 +1,43 @@ +/* + * 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 com.alipay.sofa.rpc.context; + +import com.alipay.sofa.common.insight.RecordContext; +import com.alipay.sofa.rpc.common.RemotingConstants; +import com.alipay.sofa.rpc.core.request.SofaRequest; + +import java.util.Map; + +/** + * @author Even + * @date 2024/4/29 21:03 + */ +public class RecordContextResolver { + + public static void carryWithRequest(RecordContext recordContext, SofaRequest sofaRequest) { + recordContext.setTargetServiceUniqueName(sofaRequest.getTargetServiceUniqueName()); + recordContext.setMethodName(sofaRequest.getMethodName()); + Object traceContext = sofaRequest.getRequestProp(RemotingConstants.RPC_TRACE_NAME); + if (traceContext instanceof Map) { + Map ctxMap = (Map) traceContext; + String traceId = ctxMap.get(RemotingConstants.TRACE_ID_KEY); + String rpcId = ctxMap.get(RemotingConstants.RPC_ID_KEY); + recordContext.setTraceId(traceId); + recordContext.setRpcId(rpcId); + } + } +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorRegisterEvent.java b/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorRegisterEvent.java new file mode 100644 index 000000000..fd9321260 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorRegisterEvent.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 com.alipay.sofa.rpc.event; + +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.ServerConfig; + +/** + * @author Even + * @date 2024/4/28 17:18 + */ +public class ProviderProcessorRegisterEvent implements Event { + + private final ProviderConfig providerConfig; + + private final ServerConfig serverConfig; + + public ProviderProcessorRegisterEvent(ProviderConfig providerConfig, ServerConfig serverConfig) { + this.providerConfig = providerConfig; + this.serverConfig = serverConfig; + } + + public ProviderConfig getProviderConfig() { + return providerConfig; + } + + public ServerConfig getServerConfig() { + return serverConfig; + } +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorUnRegistryEvent.java b/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorUnRegistryEvent.java new file mode 100644 index 000000000..26fb38fcd --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/event/ProviderProcessorUnRegistryEvent.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 com.alipay.sofa.rpc.event; + +import com.alipay.sofa.rpc.config.ProviderConfig; +import com.alipay.sofa.rpc.config.ServerConfig; + +/** + * @author Even + * @date 2024/4/28 17:19 + */ +public class ProviderProcessorUnRegistryEvent implements Event { + + private final ProviderConfig providerConfig; + + private final ServerConfig serverConfig; + + public ProviderProcessorUnRegistryEvent(ProviderConfig providerConfig, ServerConfig serverConfig) { + this.providerConfig = providerConfig; + this.serverConfig = serverConfig; + } + + public ProviderConfig getProviderConfig() { + return providerConfig; + } + + public ServerConfig getServerConfig() { + return serverConfig; + } +} diff --git a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java index 5939d7683..ab209534e 100644 --- a/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java +++ b/remoting/remoting-bolt/src/main/java/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java @@ -31,6 +31,7 @@ import com.alipay.sofa.rpc.common.utils.CommonUtils; import com.alipay.sofa.rpc.config.ProviderConfig; import com.alipay.sofa.rpc.config.UserThreadPoolManager; +import com.alipay.sofa.rpc.context.RecordContextResolver; import com.alipay.sofa.rpc.context.RpcInternalContext; import com.alipay.sofa.rpc.context.RpcInvokeContext; import com.alipay.sofa.rpc.context.RpcRuntimeContext; @@ -211,6 +212,7 @@ public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, SofaRequest LOGGER.errorWithApp(appName, e.getMessage(), e); } } finally { + RecordContextResolver.carryWithRequest(bizCtx.getInvokeContext().getRecordContext(), request); processingCount.decrementAndGet(); if (!isAsyncChain) { if (EventBus.isEnable(ServerEndHandleEvent.class)) { From 2ccbe7c39a0bb90a16394d40f355512ff36aeb2e Mon Sep 17 00:00:00 2001 From: evenliu Date: Wed, 22 May 2024 15:50:47 +0800 Subject: [PATCH 41/64] upgrade rpc version to 5.13.0 (#1420) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 0fc29d63f..756071449 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.0-SNAPSHOT + 5.13.0 ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 3826b3c47..f4f38057e 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.0-SNAPSHOT + 5.13.0 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 0860ef500..5d6b31d44 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -37,6 +37,6 @@ public final class Version { /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.0_20240222103719"; + public static final String BUILD_VERSION = "5.13.0_20240522142923"; } diff --git a/pom.xml b/pom.xml index eead098ca..3e3cab80f 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.0-SNAPSHOT + 5.13.0 1.33 true true From d1638201f4986f509cfb23b6543ec34a7562b421 Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 7 Jun 2024 15:45:01 +0800 Subject: [PATCH 42/64] upgrade rpc version to 5.13.1-SNAPSHOT (#1421) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 756071449..3da5e4bf6 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.0 + 5.13.1-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index f4f38057e..2413611f6 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.0 + 5.13.1-SNAPSHOT 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 5d6b31d44..849a890a0 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.13.0"; + public static final String VERSION = "5.13.1"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51300; + public static final int RPC_VERSION = 51301; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.0_20240522142923"; + public static final String BUILD_VERSION = "5.13.1_20240607152350"; } diff --git a/pom.xml b/pom.xml index 3e3cab80f..2ea91a865 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.0 + 5.13.1-SNAPSHOT 1.33 true true From ff2471e8b9d78ea0de852a3793535601b26187ed Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 29 Jul 2024 14:46:32 +0800 Subject: [PATCH 43/64] fix: set default 0 when get method timeout config (#1422) * fix: default 0 when get method timeout config * format --------- Co-authored-by: Lo1nt --- .../com/alipay/sofa/rpc/config/MethodConfig.java | 2 +- .../std/config/AbstractInterfaceConfigTest.java | 16 ++++++++++++++++ .../registry/sofa/SofaRegistryHelperTest.java | 11 +++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/MethodConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/MethodConfig.java index 611795c49..d8ab50aee 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/MethodConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/MethodConfig.java @@ -137,7 +137,7 @@ public MethodConfig setParameters(Map parameters) { * @return the timeout */ public Integer getTimeout() { - return timeout; + return timeout == null ? 0 : timeout; } /** diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java index f04724e24..881d310f9 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/std/config/AbstractInterfaceConfigTest.java @@ -23,6 +23,7 @@ import com.alipay.sofa.rpc.config.AbstractInterfaceConfig; import com.alipay.sofa.rpc.config.ApplicationConfig; import com.alipay.sofa.rpc.config.MethodConfig; +import com.alipay.sofa.rpc.config.ProviderConfig; import com.alipay.sofa.rpc.config.RegistryConfig; import com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException; import com.alipay.sofa.rpc.listener.ConfigListener; @@ -50,6 +51,21 @@ * @version : AbstractInterfaceConfigTest.java, v 0.1 2022年01月25日 4:46 下午 zhaowang */ public class AbstractInterfaceConfigTest { + @Test + public void testMethodTimeout() { + MethodConfig config = new MethodConfig(); + config.setTimeout(null); + + ProviderConfig p = new ProviderConfig(); + p.setMethods(new HashMap<>()); + p.getMethods().put("test", config); + + try { + Assert.assertFalse(p.hasTimeout()); + } catch (Exception e) { + Assert.fail("exception should not appears: " + e.getMessage()); + } + } @Test public void testDefaultValue() { diff --git a/registry/registry-sofa/src/test/java/com/alipay/sofa/rpc/registry/sofa/SofaRegistryHelperTest.java b/registry/registry-sofa/src/test/java/com/alipay/sofa/rpc/registry/sofa/SofaRegistryHelperTest.java index f00413f51..dd7951e34 100644 --- a/registry/registry-sofa/src/test/java/com/alipay/sofa/rpc/registry/sofa/SofaRegistryHelperTest.java +++ b/registry/registry-sofa/src/test/java/com/alipay/sofa/rpc/registry/sofa/SofaRegistryHelperTest.java @@ -150,6 +150,17 @@ public void convertProviderToUrls() throws Exception { Assert.assertEquals(serverConfig3.getPort(), providerInfo3.getPort()); Assert.assertEquals(providerConfig.getAppName(), providerInfo3.getAttr(ProviderInfoAttrs.ATTR_APP_NAME)); Assert.assertEquals(providerConfig.getTimeout(), providerInfo3.getDynamicAttr(ProviderInfoAttrs.ATTR_TIMEOUT)); + + ProviderConfig providerConfig2 = new ProviderConfig<>(); + providerConfig2.setMethods(new HashMap<>()); + providerConfig2.getMethods().put("test", new MethodConfig().setTimeout(null)); + Assert.assertNotNull(providerConfig2.getTimeout()); + String s4 = SofaRegistryHelper.convertProviderToUrls(providerConfig2, serverConfig); + Assert.assertNotNull(s3); + ProviderInfo providerInfo4 = SofaRegistryHelper.parseProviderInfo(s4); + Assert.assertEquals(0, providerInfo4.getDynamicAttr(".test.timeout")); + Assert.assertFalse(providerConfig2.hasTimeout()); + } @Test From 2d8190fb71a6710b7a2c2aa7df2e725c9cf91015 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Fri, 2 Aug 2024 15:50:52 +0800 Subject: [PATCH 44/64] fix: remove wrong verify logic (#1433) Co-authored-by: Lo1nt --- .../transport/netty/NettyBatchWriteQueueTest.java | 14 ++++---------- .../sofa/rpc/transport/netty/NettyChannelTest.java | 14 +++----------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java index 446544cfc..911ee1065 100644 --- a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java +++ b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyBatchWriteQueueTest.java @@ -23,9 +23,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -37,20 +35,16 @@ */ public class NettyBatchWriteQueueTest { - @Mock - private Channel mockChannel; + private Channel mockChannel = Mockito.mock(Channel.class); - @Mock - private EventLoop mockEventLoop; + private EventLoop mockEventLoop = Mockito.mock(EventLoop.class); - @Mock - private ChannelPromise mockChannelPromise; + private ChannelPromise mockChannelPromise = Mockito.mock(ChannelPromise.class); - private NettyBatchWriteQueue nettyBatchWriteQueue; + private NettyBatchWriteQueue nettyBatchWriteQueue = Mockito.mock(NettyBatchWriteQueue.class); @Before public void setUp() { - MockitoAnnotations.initMocks(this); when(mockChannel.eventLoop()).thenReturn(mockEventLoop); when(mockChannel.newPromise()).thenReturn(mockChannelPromise); nettyBatchWriteQueue = NettyBatchWriteQueue.createWriteQueue(mockChannel); diff --git a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java index e5be4aec6..83846eab9 100644 --- a/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java +++ b/remoting/remoting-http/src/test/java/com/alipay/sofa/rpc/transport/netty/NettyChannelTest.java @@ -16,7 +16,6 @@ */ package com.alipay.sofa.rpc.transport.netty; -import com.alipay.sofa.rpc.common.utils.NetUtils; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -27,13 +26,9 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.Mockito; -import java.net.InetSocketAddress; - import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; /** @@ -42,16 +37,12 @@ */ public class NettyChannelTest { - @Mock private Channel mockChannel = Mockito.mock(Channel.class); - @Mock private ChannelHandlerContext mockContext = Mockito.mock(ChannelHandlerContext.class); - @Mock private NettyBatchWriteQueue mockWriteQueue = Mockito.mock(NettyBatchWriteQueue.class); - @Mock private ChannelFuture mockFuture = Mockito.mock(ChannelFuture.class); private NettyChannel nettyChannel; @@ -62,6 +53,7 @@ public void setUp() { Mockito.when(mockChannel.alloc()).thenReturn(PooledByteBufAllocator.DEFAULT); when(mockContext.channel()).thenReturn(mockChannel); when(mockWriteQueue.enqueue(any())).thenReturn(mockFuture); + nettyChannel = new NettyChannel(mockChannel); nettyChannel.setWriteQueue(mockWriteQueue); } @@ -80,8 +72,8 @@ public void testRunSuccess() throws Exception { listener.operationComplete((Future) mockFuture); // 验证没有错误日志被记录(因为操作是成功的) - Mockito.verify(Mockito.mock(NetUtils.class), times(10)); - NetUtils.channelToString(any(InetSocketAddress.class), any(InetSocketAddress.class)); + // Mockito.verify(Mockito.mock(NetUtils.class), times(10)); + // NetUtils.channelToString(any(InetSocketAddress.class), any(InetSocketAddress.class)); } } From 46d1dcd1ea0ae6bc3865dcf9850c4cffa4c2486e Mon Sep 17 00:00:00 2001 From: yuanyuancin Date: Fri, 16 Aug 2024 03:37:06 -0500 Subject: [PATCH 45/64] Jackson serialization for multi classloader (#1438) * jackson serialization for multi classloader * clear cache --------- Co-authored-by: yuanyuan --- .../sofa/rpc/codec/jackson/JacksonHelper.java | 35 ++++++++++++++----- .../rpc/codec/jackson/JacksonSerializer.java | 3 ++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonHelper.java b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonHelper.java index b764a31e9..0078f7e36 100644 --- a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonHelper.java +++ b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonHelper.java @@ -18,6 +18,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.alipay.sofa.rpc.common.utils.ClassUtils; @@ -27,6 +28,8 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; +import static com.alipay.sofa.rpc.common.utils.ClassLoaderUtils.getCurrentClassLoader; + /** * @author zhiyuan.lzy */ @@ -37,12 +40,12 @@ public class JacksonHelper { /** * Request service and method cache {service+method:class} */ - private ConcurrentHashMap requestClassCache = new ConcurrentHashMap(); + private ConcurrentHashMap> requestClassCache = new ConcurrentHashMap<>(); /** * Response service and method cache {service+method:class} */ - private ConcurrentHashMap responseClassCache = new ConcurrentHashMap(); + private ConcurrentHashMap> responseClassCache = new ConcurrentHashMap<>(); /** * Fetch request class for cache according service and method @@ -54,14 +57,30 @@ public class JacksonHelper { public JavaType[] getReqClass(String service, String methodName) { String key = buildMethodKey(service, methodName); - Type[] reqClassList = requestClassCache.get(key); + Type[] reqClassList = getRequestCache().get(key); if (reqClassList == null) { //read interface and method from cache String interfaceClass = ConfigUniqueNameGenerator.getInterfaceName(service); Class clazz = ClassUtils.forName(interfaceClass, true); loadClassToCache(key, clazz, methodName); } - return requestClassCache.get(key); + return getRequestCache().get(key); + } + + private Map getRequestCache() { + return requestClassCache.computeIfAbsent(getCurrentClassLoader(), k -> new ConcurrentHashMap<>()); + } + + private Map getResponseCache() { + return responseClassCache.computeIfAbsent(getCurrentClassLoader(), k -> new ConcurrentHashMap<>()); + } + + public void clearCache(ClassLoader classLoader) { + if (classLoader == null) { + return; + } + requestClassCache.remove(classLoader); + responseClassCache.remove(classLoader); } /** @@ -73,14 +92,14 @@ public JavaType[] getReqClass(String service, String methodName) { */ public JavaType getResClass(String service, String methodName) { String key = service + "#" + methodName; - JavaType reqType = responseClassCache.get(key); + JavaType reqType = getResponseCache().get(key); if (reqType == null) { // 读取接口里的方法参数和返回值 String interfaceClass = ConfigUniqueNameGenerator.getInterfaceName(service); Class clazz = ClassUtils.forName(interfaceClass, true); loadClassToCache(key, clazz, methodName); } - return responseClassCache.get(key); + return getResponseCache().get(key); } /** @@ -122,7 +141,7 @@ private void loadClassToCache(String key, Class clazz, String methodName) { JavaType javaType = mapper.getTypeFactory().constructType(parameterTypes[i]); javaTypes[i] = javaType; } - requestClassCache.put(key, javaTypes); + getRequestCache().put(key, javaTypes); // parse response types Type resType = jsonMethod.getGenericReturnType(); @@ -130,6 +149,6 @@ private void loadClassToCache(String key, Class clazz, String methodName) { throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_VOID_RETURN, "jackson", clazz.getName())); } JavaType resJavaType = mapper.getTypeFactory().constructType(resType); - responseClassCache.put(key, resJavaType); + getResponseCache().put(key, resJavaType); } } diff --git a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java index 66ebb5741..1f9ded9ff 100644 --- a/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java +++ b/codec/codec-jackson/src/main/java/com/alipay/sofa/rpc/codec/jackson/JacksonSerializer.java @@ -395,4 +395,7 @@ protected ObjectMapper getMapper() { return this.mapper; } + public void clearCache(ClassLoader classLoader) { + jacksonHelper.clearCache(classLoader); + } } From b140ee6435ff37fcaea965657313d9e7cd9529eb Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 16 Aug 2024 16:42:25 +0800 Subject: [PATCH 46/64] enhance log format (#1436) Co-authored-by: liujianjun.ljj --- .../src/main/java/com/alipay/sofa/rpc/log/LogCodes.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/log/LogCodes.java b/core/api/src/main/java/com/alipay/sofa/rpc/log/LogCodes.java index d42c83b5d..4188dc49d 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/log/LogCodes.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/log/LogCodes.java @@ -393,7 +393,7 @@ public static String getLog(String code) { return CODE_DOES_NOT_EXIST + code; } try { - return String.format(LOG, code, LOG_CODES.get(code), LogCodes.NOTE); + return format(code, LOG_CODES.get(code), LogCodes.NOTE); } catch (Throwable e) { LOGGER.error(LOG_FORMAT_ERROR + code, e); } @@ -428,7 +428,7 @@ public static String getLog(String code, Object... messages) { } try { - return String.format(LOG, code, MessageFormat.format(message, messages), LogCodes.NOTE); + return format(code, MessageFormat.format(message, messages), LogCodes.NOTE); } catch (Throwable e) { LOGGER.error(LOG_FORMAT_ERROR + code, e); } @@ -456,4 +456,9 @@ public static String getLiteLog(String codeOrMsg, Object... messages) { } return LITE_LOG_FORMAT_ERROR + codeOrMsg; } + + private static String format(String code, String message, String note) { + return "RPC-" + code + ": " + message + " " + note; + } + } From cdbd574857c722309f31e4b65f3931479304ca86 Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 16 Aug 2024 17:14:27 +0800 Subject: [PATCH 47/64] enhance log format (#1437) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 3da5e4bf6..7784ab7b1 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.1-SNAPSHOT + 5.13.1 ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 2413611f6..9991cc70d 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.1-SNAPSHOT + 5.13.1 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 849a890a0..113b9cef3 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -37,6 +37,6 @@ public final class Version { /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.1_20240607152350"; + public static final String BUILD_VERSION = "5.13.1_20240815203044"; } diff --git a/pom.xml b/pom.xml index 2ea91a865..4b9bfb52d 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.1-SNAPSHOT + 5.13.1 1.33 true true From bb823e98407d07795d14f2d938008439c090f87a Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 19 Aug 2024 18:01:06 +0800 Subject: [PATCH 48/64] update hessian and tracer version (#1439) Co-authored-by: liujianjun.ljj --- all/pom.xml | 4 ++-- bom/pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 7784ab7b1..502f6dfcf 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -59,10 +59,10 @@ 1.4.0 3.29.2-GA 4.1.44.Final - 3.5.3 + 3.5.4 3.6.3.Final 1.6.10 - 3.0.8 + 3.1.6 1.4.1 1.9.8 6.3.0 diff --git a/bom/pom.xml b/bom/pom.xml index 9991cc70d..3ad5d01a3 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -32,7 +32,7 @@ 32.0.0-jre 0.16.0 - 3.5.3 + 3.5.4 0.9.2 3.22.0 2.12.7 @@ -55,7 +55,7 @@ 1.6.10 1.4.0 - 3.0.8 + 3.1.6 1.4.1 true From d5b8c507f3c647c0bb2e377cc02f13a2974964e6 Mon Sep 17 00:00:00 2001 From: evenliu Date: Thu, 19 Sep 2024 11:03:16 +0800 Subject: [PATCH 49/64] update hessian version to 3.5.5 (#1445) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 502f6dfcf..b3b0d744d 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -59,7 +59,7 @@ 1.4.0 3.29.2-GA 4.1.44.Final - 3.5.4 + 3.5.5 3.6.3.Final 1.6.10 3.1.6 diff --git a/bom/pom.xml b/bom/pom.xml index 3ad5d01a3..5c618e403 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -32,7 +32,7 @@ 32.0.0-jre 0.16.0 - 3.5.4 + 3.5.5 0.9.2 3.22.0 2.12.7 From 90dc97c4135ebfbe7f1685ba97d9b1cf13ec77d5 Mon Sep 17 00:00:00 2001 From: evenliu Date: Thu, 26 Sep 2024 15:50:09 +0800 Subject: [PATCH 50/64] Update rpc version 051302 ss (#1448) * update hessian version to 3.5.5 * update rpc version to 5.13.2-SNAPSHOT --------- Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index b3b0d744d..ac7eb4c6f 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.1 + 5.13.2-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 5c618e403..82305e05c 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.1 + 5.13.2-SNAPSHOT 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 113b9cef3..979c0e1cf 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.13.1"; + public static final String VERSION = "5.13.2"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51301; + public static final int RPC_VERSION = 51302; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.1_20240815203044"; + public static final String BUILD_VERSION = "5.13.2_20240922142359"; } diff --git a/pom.xml b/pom.xml index 4b9bfb52d..9725bf743 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.1 + 5.13.2-SNAPSHOT 1.33 true true From 29999af3bb2bb648ee72947b446eb26c8cda2d1f Mon Sep 17 00:00:00 2001 From: evenliu Date: Tue, 8 Oct 2024 14:46:17 +0800 Subject: [PATCH 51/64] Remove lookout (#1447) * update hessian version to 3.5.5 * remove lookout * update registry version --------- Co-authored-by: liujianjun.ljj --- all/pom.xml | 14 +- bom/pom.xml | 14 +- .../alipay/sofa/rpc/common/RpcOptions.java | 1 + metrics/metrics-lookout/pom.xml | 107 --- .../sofa/rpc/event/LookoutSubscriber.java | 199 ------ .../lookout/RpcAbstractLookoutModel.java | 164 ----- .../lookout/RpcClientLookoutModel.java | 101 --- .../sofa/rpc/metrics/lookout/RpcLookout.java | 354 ---------- .../rpc/metrics/lookout/RpcLookoutId.java | 179 ----- .../lookout/RpcServerLookoutModel.java | 59 -- .../alipay/sofa/rpc/module/LookoutModule.java | 71 -- .../com.alipay.sofa.rpc.module.Module | 1 - .../sofa/rpc/module/ConsumerSubTest.java | 71 -- .../sofa/rpc/module/LookoutModuleTest.java | 33 - .../sofa/rpc/module/ProviderPubTest.java | 68 -- metrics/pom.xml | 1 - registry/registry-sofa/pom.xml | 5 - test/test-integration/pom.xml | 12 - .../rpc/metrics/lookout/LookoutService.java | 33 - .../metrics/lookout/LookoutServiceImpl.java | 72 -- .../rpc/metrics/lookout/RpcLookoutTest.java | 637 ------------------ .../sofa/rpc/server/rest/RestLookoutTest.java | 354 ---------- 22 files changed, 3 insertions(+), 2547 deletions(-) delete mode 100644 metrics/metrics-lookout/pom.xml delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcAbstractLookoutModel.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcClientLookoutModel.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookout.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcServerLookoutModel.java delete mode 100644 metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/module/LookoutModule.java delete mode 100644 metrics/metrics-lookout/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.module.Module delete mode 100644 metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ConsumerSubTest.java delete mode 100644 metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/LookoutModuleTest.java delete mode 100644 metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ProviderPubTest.java delete mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutService.java delete mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutServiceImpl.java delete mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutTest.java delete mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/server/rest/RestLookoutTest.java diff --git a/all/pom.xml b/all/pom.xml index ac7eb4c6f..b47e12d07 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -63,9 +63,8 @@ 3.6.3.Final 1.6.10 3.1.6 - 1.4.1 1.9.8 - 6.3.0 + 6.5.6 1.6.9 7.0 4.5.13 @@ -285,11 +284,6 @@ sofa-rpc-tracer-opentracing-triple ${project.version} - - com.alipay.sofa - sofa-rpc-metrics-lookout - ${project.version} - com.alipay.sofa sofa-rpc-metrics-micrometer @@ -376,11 +370,6 @@ resteasy-jackson2-provider ${resteasy.version} - - com.alipay.sofa.lookout - lookout-api - ${lookout.version} - io.swagger swagger-core @@ -545,7 +534,6 @@ com.alipay.sofa:sofa-rpc-fault-tolerance com.alipay.sofa:sofa-rpc-fault-hystrix com.alipay.sofa:sofa-rpc-log-common-tools - com.alipay.sofa:sofa-rpc-metrics-lookout com.alipay.sofa:sofa-rpc-metrics-micrometer com.alipay.sofa:sofa-rpc-metrics-prometheus com.alipay.sofa:sofa-rpc-registry-consul diff --git a/bom/pom.xml b/bom/pom.xml index 82305e05c..7f7c3f10f 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -25,7 +25,7 @@ 0.22.0 3.1.11 2.0.3 - 6.3.0 + 6.5.6 1.2.2 1.6.9 7.0 @@ -56,7 +56,6 @@ 1.6.10 1.4.0 3.1.6 - 1.4.1 true true @@ -472,17 +471,6 @@ tracer-core ${tracer.version} - - - com.alipay.sofa.lookout - lookout-api - ${lookout.version} - - - com.alipay.sofa.lookout - lookout-core - ${lookout.version} - io.micrometer diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java index 46c43206c..ff9ebebd3 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java @@ -529,6 +529,7 @@ public class RpcOptions { /** * Whether to close lookout collection. */ + @Deprecated public static final String LOOKOUT_COLLECT_DISABLE = "lookout.collect.disable"; /** diff --git a/metrics/metrics-lookout/pom.xml b/metrics/metrics-lookout/pom.xml deleted file mode 100644 index d8696fa0b..000000000 --- a/metrics/metrics-lookout/pom.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - sofa-rpc-metrics - com.alipay.sofa - ${revision} - - 4.0.0 - - sofa-rpc-metrics-lookout - - - - - - com.alipay.sofa - sofa-rpc-log-common-tools - ${project.parent.version} - - - - - com.alipay.sofa.lookout - lookout-api - - - - - com.alipay.sofa.lookout - lookout-core - test - - - - org.slf4j - slf4j-log4j12 - test - - - junit - junit - test - - - - - src/main/java - - - src/main/resources - false - - **/** - - - - src/test/java - - - src/test/resources - false - - **/** - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${maven.compiler.source} - ${maven.compiler.target} - ${project.build.sourceEncoding} - - - - org.apache.maven.plugins - maven-install-plugin - - ${module.install.skip} - - - - org.apache.maven.plugins - maven-deploy-plugin - - ${module.deploy.skip} - - - - org.apache.maven.plugins - maven-surefire-plugin - - ${skipTests} - - **/*Test.java - - once - - - - - diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java deleted file mode 100644 index 51f292f92..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/event/LookoutSubscriber.java +++ /dev/null @@ -1,199 +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 com.alipay.sofa.rpc.event; - -import com.alipay.sofa.rpc.common.RemotingConstants; -import com.alipay.sofa.rpc.common.RpcConfigs; -import com.alipay.sofa.rpc.common.RpcConstants; -import com.alipay.sofa.rpc.common.RpcOptions; -import com.alipay.sofa.rpc.context.RpcInternalContext; -import com.alipay.sofa.rpc.context.RpcRunningState; -import com.alipay.sofa.rpc.core.request.SofaRequest; -import com.alipay.sofa.rpc.core.response.SofaResponse; -import com.alipay.sofa.rpc.metrics.lookout.RpcClientLookoutModel; -import com.alipay.sofa.rpc.metrics.lookout.RpcLookout; -import com.alipay.sofa.rpc.metrics.lookout.RpcServerLookoutModel; - -/** - * Collect the raw information for lookout by listening to events. - * - * @author LiWei.Liangen - */ -public class LookoutSubscriber extends Subscriber { - - /** - * Whether lookout be banned from collecting information. - */ - public static boolean lookoutCollectDisable = RpcConfigs - .getBooleanValue(RpcOptions.LOOKOUT_COLLECT_DISABLE); - - private final RpcLookout rpcMetrics = new RpcLookout(); - - public LookoutSubscriber() { - super(false); - } - - @Override - public void onEvent(Event event) { - - if (RpcRunningState.isUnitTestMode() || lookoutCollectDisable) { - return; - } - - Class eventClass = event.getClass(); - - if (eventClass == ClientEndInvokeEvent.class) { - - ClientEndInvokeEvent clientEndInvokeEvent = (ClientEndInvokeEvent) event; - - RpcClientLookoutModel rpcClientMetricsModel = createClientMetricsModel(clientEndInvokeEvent.getRequest(), - clientEndInvokeEvent.getResponse()); - - rpcMetrics.collectClient(rpcClientMetricsModel); - - } else if (eventClass == ServerSendEvent.class) { - - ServerSendEvent serverSendEvent = (ServerSendEvent) event; - - RpcServerLookoutModel rpcServerMetricsModel = createServerMetricsModel(serverSendEvent.getRequest(), - serverSendEvent.getResponse()); - - rpcMetrics.collectServer(rpcServerMetricsModel); - - } else if (eventClass == ServerStartedEvent.class) { - - ServerStartedEvent serverStartedEvent = (ServerStartedEvent) event; - - if (serverStartedEvent.getThreadPoolExecutor() != null) { - rpcMetrics.collectThreadPool(serverStartedEvent.getServerConfig(), - serverStartedEvent.getThreadPoolExecutor()); - } - - } else if (eventClass == ServerStoppedEvent.class) { - ServerStoppedEvent serverStartedEvent = (ServerStoppedEvent) event; - rpcMetrics.removeThreadPool(serverStartedEvent.getServerConfig()); - } else if (eventClass == ProviderPubEvent.class) { - ProviderPubEvent providerPubEvent = (ProviderPubEvent) event; - rpcMetrics.collectProvderPubInfo(providerPubEvent.getProviderConfig()); - } - else if (eventClass == ConsumerSubEvent.class) { - ConsumerSubEvent consumerSubEvent = (ConsumerSubEvent) event; - rpcMetrics.collectConsumerSubInfo(consumerSubEvent.getConsumerConfig()); - } - } - - /** - * create RpcClientLookoutModel - * @param request - * @param response - * @return - */ - private RpcClientLookoutModel createClientMetricsModel(SofaRequest request, SofaResponse response) { - - RpcClientLookoutModel clientMetricsModel = new RpcClientLookoutModel(); - - RpcInternalContext context = RpcInternalContext.getContext(); - - String app = getStringAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_APP_NAME)); - String service = request.getTargetServiceUniqueName(); - String method = request.getMethodName(); - String protocol = getStringAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_PROTOCOL_NAME)); - String invokeType = request.getInvokeType(); - String targetApp = request.getTargetAppName(); - Long requestSize = getLongAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_REQ_SIZE)); - Long responseSize = getLongAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_RESP_SIZE)); - Long elapsedTime = getLongAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_CLIENT_ELAPSE)); - Boolean success = response != null && !response.isError() && response.getErrorMsg() == null && - (!(response.getAppResponse() instanceof Throwable)); - - clientMetricsModel.setApp(app); - clientMetricsModel.setService(service); - clientMetricsModel.setMethod(method); - clientMetricsModel.setProtocol(protocol); - clientMetricsModel.setInvokeType(invokeType); - clientMetricsModel.setTargetApp(targetApp); - clientMetricsModel.setRequestSize(requestSize); - clientMetricsModel.setResponseSize(responseSize); - clientMetricsModel.setElapsedTime(elapsedTime); - clientMetricsModel.setSuccess(success); - - return clientMetricsModel; - } - - /** - * create RpcServerLookoutModel - * @param request - * @param response - * @return - */ - private RpcServerLookoutModel createServerMetricsModel(SofaRequest request, SofaResponse response) { - - RpcServerLookoutModel rpcServerMetricsModel = new RpcServerLookoutModel(); - - RpcInternalContext context = RpcInternalContext.getContext(); - - String app = request.getTargetAppName(); - String service = request.getTargetServiceUniqueName(); - String method = request.getMethodName(); - String protocol = getStringAvoidNull(request.getRequestProp(RemotingConstants.HEAD_PROTOCOL)); - String invokeType = request.getInvokeType(); - String callerApp = getStringAvoidNull(request.getRequestProp(RemotingConstants.HEAD_APP_NAME)); - Long elapsedTime = getLongAvoidNull(context.getAttachment(RpcConstants.INTERNAL_KEY_IMPL_ELAPSE)); - boolean success = response != null && !response.isError() && response.getErrorMsg() == null && - (!(response.getAppResponse() instanceof Throwable)); - - rpcServerMetricsModel.setApp(app); - rpcServerMetricsModel.setService(service); - rpcServerMetricsModel.setMethod(method); - rpcServerMetricsModel.setProtocol(protocol); - rpcServerMetricsModel.setInvokeType(invokeType); - rpcServerMetricsModel.setCallerApp(callerApp); - rpcServerMetricsModel.setElapsedTime(elapsedTime); - rpcServerMetricsModel.setSuccess(success); - - return rpcServerMetricsModel; - } - - private String getStringAvoidNull(Object object) { - if (object == null) { - return null; - } - - return (String) object; - - } - - private Long getLongAvoidNull(Object object) { - if (object == null) { - return null; - } - - if (object instanceof Integer) { - return Long.parseLong(object.toString()); - } - - return (Long) object; - } - - public static boolean isLookoutCollectDisable() { - return lookoutCollectDisable; - } - - public static void setLookoutCollectDisable(boolean lookoutCollectDisable) { - LookoutSubscriber.lookoutCollectDisable = lookoutCollectDisable; - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcAbstractLookoutModel.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcAbstractLookoutModel.java deleted file mode 100644 index 72d4ec773..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcAbstractLookoutModel.java +++ /dev/null @@ -1,164 +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 com.alipay.sofa.rpc.metrics.lookout; - -/** - * - * @author LiWei.Liangen - */ -public class RpcAbstractLookoutModel { - - protected String app; - - protected String service; - - protected String method; - - protected String protocol; - - protected String invokeType; - - protected Long elapsedTime; - - protected boolean success; - - /** - * Getter method for property app. - * - * @return property value of app - */ - public String getApp() { - return app; - } - - /** - * Setter method for property app. - * - * @param app value to be assigned to property app - */ - public void setApp(String app) { - this.app = app; - } - - /** - * Getter method for property service. - * - * @return property value of service - */ - public String getService() { - return service; - } - - /** - * Setter method for property service. - * - * @param service value to be assigned to property service - */ - public void setService(String service) { - this.service = service; - } - - /** - * Getter method for property method. - * - * @return property value of method - */ - public String getMethod() { - return method; - } - - /** - * Setter method for property method. - * - * @param method value to be assigned to property method - */ - public void setMethod(String method) { - this.method = method; - } - - /** - * Getter method for property protocol. - * - * @return property value of protocol - */ - public String getProtocol() { - return protocol; - } - - /** - * Setter method for property protocol. - * - * @param protocol value to be assigned to property protocol - */ - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - /** - * Getter method for property invokeType. - * - * @return property value of invokeType - */ - public String getInvokeType() { - return invokeType; - } - - /** - * Setter method for property invokeType. - * - * @param invokeType value to be assigned to property invokeType - */ - public void setInvokeType(String invokeType) { - this.invokeType = invokeType; - } - - /** - * Getter method for property elapsedTime. - * - * @return property value of elapsedTime - */ - public Long getElapsedTime() { - return elapsedTime; - } - - /** - * Setter method for property elapsedTime. - * - * @param elapsedTime value to be assigned to property elapsedTime - */ - public void setElapsedTime(Long elapsedTime) { - this.elapsedTime = elapsedTime; - } - - /** - * Getter method for property success. - * - * @return property value of success - */ - public boolean getSuccess() { - return success; - } - - /** - * Setter method for property success. - * - * @param success value to be assigned to property success - */ - public void setSuccess(boolean success) { - this.success = success; - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcClientLookoutModel.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcClientLookoutModel.java deleted file mode 100644 index 1128934c1..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcClientLookoutModel.java +++ /dev/null @@ -1,101 +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 com.alipay.sofa.rpc.metrics.lookout; - -/** - * The model for lookout info of client - * - * @author LiWei.Liangen - */ -public class RpcClientLookoutModel extends RpcAbstractLookoutModel { - - protected String targetApp; - - protected Long requestSize; - - protected Long responseSize; - - /** - * Getter method for property targetApp. - * - * @return property value of targetApp - */ - public String getTargetApp() { - return targetApp; - } - - /** - * Setter method for property targetApp. - * - * @param targetApp value to be assigned to property targetApp - */ - public void setTargetApp(String targetApp) { - this.targetApp = targetApp; - } - - /** - * Getter method for property requestSize. - * - * @return property value of requestSize - */ - public Long getRequestSize() { - return requestSize; - } - - /** - * Setter method for property requestSize. - * - * @param requestSize value to be assigned to property requestSize - */ - public void setRequestSize(Long requestSize) { - this.requestSize = requestSize; - } - - /** - * Getter method for property responseSize. - * - * @return property value of responseSize - */ - public Long getResponseSize() { - return responseSize; - } - - /** - * Setter method for property responseSize. - * - * @param responseSize value to be assigned to property responseSize - */ - public void setResponseSize(Long responseSize) { - this.responseSize = responseSize; - } - - @Override - public String toString() { - return "RpcClientLookoutModel{" + - "targetApp='" + targetApp + '\'' + - ", requestSize=" + requestSize + - ", responseSize=" + responseSize + - ", app='" + app + '\'' + - ", service='" + service + '\'' + - ", method='" + method + '\'' + - ", protocol='" + protocol + '\'' + - ", invokeType='" + invokeType + '\'' + - ", elapsedTime=" + elapsedTime + - ", success=" + success + - '}'; - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookout.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookout.java deleted file mode 100644 index 64f878c91..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookout.java +++ /dev/null @@ -1,354 +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 com.alipay.sofa.rpc.metrics.lookout; - -import com.alipay.lookout.api.Counter; -import com.alipay.lookout.api.DistributionSummary; -import com.alipay.lookout.api.Gauge; -import com.alipay.lookout.api.Id; -import com.alipay.lookout.api.Lookout; -import com.alipay.lookout.api.Timer; -import com.alipay.lookout.api.composite.MixinMetric; -import com.alipay.lookout.api.info.Info; -import com.alipay.sofa.rpc.common.utils.StringUtils; -import com.alipay.sofa.rpc.config.ConsumerConfig; -import com.alipay.sofa.rpc.config.ProviderConfig; -import com.alipay.sofa.rpc.config.ServerConfig; -import com.alipay.sofa.rpc.log.LogCodes; -import com.alipay.sofa.rpc.log.Logger; -import com.alipay.sofa.rpc.log.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * Rpc reports the information to lookout. - * - * @author LiWei.Liangen - */ -public class RpcLookout { - - /** - * slf4j Logger for this class - */ - private final static Logger LOGGER = LoggerFactory.getLogger(RpcLookout.class); - - private final RpcLookoutId rpcLookoutId = new RpcLookoutId(); - - /** - * Collect the RPC client information. - * - * @param rpcClientMetricsModel client information model - */ - public void collectClient(RpcClientLookoutModel rpcClientMetricsModel) { - - try { - Id methodConsumerId = createMethodConsumerId(rpcClientMetricsModel); - MixinMetric methodConsumerMetric = Lookout.registry().mixinMetric(methodConsumerId); - - recordCounterAndTimer(methodConsumerMetric, rpcClientMetricsModel); - - recordSize(methodConsumerMetric, rpcClientMetricsModel); - - } catch (Throwable t) { - LOGGER.error(LogCodes.getLog(LogCodes.ERROR_METRIC_REPORT_ERROR), t); - } - } - - /** - * Collect the RPC server information. - * - * @param rpcServerMetricsModel server information model - */ - public void collectServer(RpcServerLookoutModel rpcServerMetricsModel) { - - try { - Id methodProviderId = createMethodProviderId(rpcServerMetricsModel); - MixinMetric methodProviderMetric = Lookout.registry().mixinMetric(methodProviderId); - - recordCounterAndTimer(methodProviderMetric, rpcServerMetricsModel); - - } catch (Throwable t) { - LOGGER.error(LogCodes.getLog(LogCodes.ERROR_METRIC_REPORT_ERROR), t); - } - } - - /** - * Collect the thread pool information - * - * @param serverConfig ServerConfig - * @param threadPoolExecutor ThreadPoolExecutor - */ - public void collectThreadPool(ServerConfig serverConfig, final ThreadPoolExecutor threadPoolExecutor) { - try { - - int coreSize = serverConfig.getCoreThreads(); - int maxSize = serverConfig.getMaxThreads(); - int queueSize = serverConfig.getQueues(); - - final ThreadPoolConfig threadPoolConfig = new ThreadPoolConfig(coreSize, maxSize, queueSize); - - Lookout.registry().info(rpcLookoutId.fetchServerThreadConfigId(serverConfig), new Info() { - - @Override - public ThreadPoolConfig value() { - return threadPoolConfig; - } - }); - - Lookout.registry().gauge(rpcLookoutId.fetchServerThreadPoolActiveCountId(serverConfig), - new Gauge() { - - @Override - public Integer value() { - return threadPoolExecutor.getActiveCount(); - } - }); - - Lookout.registry().gauge(rpcLookoutId.fetchServerThreadPoolIdleCountId(serverConfig), new Gauge() { - - @Override - public Integer value() { - return threadPoolExecutor.getPoolSize() - threadPoolExecutor.getActiveCount(); - } - }); - - Lookout.registry().gauge(rpcLookoutId.fetchServerThreadPoolQueueSizeId(serverConfig), new Gauge() { - - @Override - public Integer value() { - return threadPoolExecutor.getQueue().size(); - } - }); - } catch (Throwable t) { - LOGGER.error(LogCodes.getLog(LogCodes.ERROR_METRIC_REPORT_ERROR), t); - } - } - - /** - * remove the thread pool information - * - * @param serverConfig server config - */ - public void removeThreadPool(ServerConfig serverConfig) { - Lookout.registry().removeMetric(rpcLookoutId.removeServerThreadConfigId(serverConfig)); - Lookout.registry().removeMetric(rpcLookoutId.removeServerThreadPoolActiveCountId(serverConfig)); - Lookout.registry().removeMetric(rpcLookoutId.removeServerThreadPoolIdleCountId(serverConfig)); - Lookout.registry().removeMetric(rpcLookoutId.removeServerThreadPoolQueueSizeId(serverConfig)); - } - - /** - * Record the number of calls and time consuming. - * - * @param mixinMetric MixinMetric - * @param model information model - */ - private void recordCounterAndTimer(MixinMetric mixinMetric, RpcAbstractLookoutModel model) { - Counter totalCounter = mixinMetric.counter("total_count"); - Timer totalTimer = mixinMetric.timer("total_time"); - - Long elapsedTime = model.getElapsedTime(); - - totalCounter.inc(); - if (elapsedTime != null) { - totalTimer.record(elapsedTime, TimeUnit.MILLISECONDS); - } - - if (!model.getSuccess()) { - Counter failCounter = mixinMetric.counter("fail_count"); - Timer failTimer = mixinMetric.timer("fail_time"); - - failCounter.inc(); - if (elapsedTime != null) { - failTimer.record(elapsedTime, TimeUnit.MILLISECONDS); - } - } - } - - /** - * Record request size and response size - * - * @param mixinMetric MixinMetric - * @param model information model - */ - private void recordSize(MixinMetric mixinMetric, RpcClientLookoutModel model) { - - Long requestSize = model.getRequestSize(); - Long responseSize = model.getResponseSize(); - - if (requestSize != null) { - DistributionSummary requestSizeDS = mixinMetric.distributionSummary("request_size"); - requestSizeDS.record(model.getRequestSize()); - } - - if (responseSize != null) { - DistributionSummary responseSizeDS = mixinMetric.distributionSummary("response_size"); - responseSizeDS.record(model.getResponseSize()); - } - } - - /** - * Create consumer id - * - * @param model RpcClientLookoutModel - * @return Id - */ - private Id createMethodConsumerId(RpcClientLookoutModel model) { - - Map tags = new HashMap(6); - - tags.put("app", StringUtils.defaultString(model.getApp())); - tags.put("service", StringUtils.defaultString(model.getService())); - tags.put("method", StringUtils.defaultString(model.getMethod())); - tags.put("protocol", StringUtils.defaultString(model.getProtocol())); - tags.put("invoke_type", StringUtils.defaultString(model.getInvokeType())); - tags.put("target_app", StringUtils.defaultString(model.getTargetApp())); - - return rpcLookoutId.fetchConsumerStatId(tags); - } - - /** - * Create provider id - * - * @param model RpcServerLookoutModel - * @return Id - */ - public Id createMethodProviderId(RpcServerLookoutModel model) { - Map tags = new HashMap(5); - tags.put("app", StringUtils.defaultString(model.getApp())); - tags.put("service", StringUtils.defaultString(model.getService())); - tags.put("method", StringUtils.defaultString(model.getMethod())); - tags.put("protocol", StringUtils.defaultString(model.getProtocol())); - tags.put("caller_app", StringUtils.defaultString(model.getCallerApp())); - - return rpcLookoutId.fetchProviderStatId(tags); - } - - /** - * Collect the RPC client information. - * - * @param providerConfig client information model - */ - public void collectProvderPubInfo(final ProviderConfig providerConfig) { - - try { - Id providerConfigId = rpcLookoutId.fetchProviderPubId(); - Lookout.registry().info(providerConfigId, new Info() { - @Override - public ProviderConfig value() { - return providerConfig; - } - }); - } catch (Throwable t) { - LOGGER.error(LogCodes.getLog(LogCodes.ERROR_METRIC_REPORT_ERROR), t); - } - } - - /** - * Collect the RPC client information. - * - * @param consumerConfig client information model - */ - public void collectConsumerSubInfo(final ConsumerConfig consumerConfig) { - - try { - Id consumerConfigId = rpcLookoutId.fetchConsumerSubId(); - Lookout.registry().info(consumerConfigId, new Info() { - @Override - public ConsumerConfig value() { - return consumerConfig; - } - }); - } catch (Throwable t) { - LOGGER.error(LogCodes.getLog(LogCodes.ERROR_METRIC_REPORT_ERROR), t); - } - } - - /** - * Thread pool static configuration information. - */ - private class ThreadPoolConfig { - - private int corePoolSize; - - private int maxPoolSize; - - private int queueSize; - - public ThreadPoolConfig(int corePoolSize, int maxPoolSize, int queueSize) { - this.corePoolSize = corePoolSize; - this.maxPoolSize = maxPoolSize; - this.queueSize = queueSize; - } - - /** - * Getter method for property corePoolSize. - * - * @return property value of corePoolSize - */ - public int getCorePoolSize() { - return corePoolSize; - } - - /** - * Setter method for property corePoolSize. - * - * @param corePoolSize value to be assigned to property corePoolSize - */ - public void setCorePoolSize(int corePoolSize) { - this.corePoolSize = corePoolSize; - } - - /** - * Getter method for property maxPoolSize. - * - * @return property value of maxPoolSize - */ - public int getMaxPoolSize() { - return maxPoolSize; - } - - /** - * Setter method for property maxPoolSize. - * - * @param maxPoolSize value to be assigned to property maxPoolSize - */ - public void setMaxPoolSize(int maxPoolSize) { - this.maxPoolSize = maxPoolSize; - } - - /** - * Getter method for property queueSize. - * - * @return property value of queueSize - */ - public int getQueueSize() { - return queueSize; - } - - /** - * Setter method for property queueSize. - * - * @param queueSize value to be assigned to property queueSize - */ - public void setQueueSize(int queueSize) { - this.queueSize = queueSize; - } - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java deleted file mode 100644 index e9d406d78..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutId.java +++ /dev/null @@ -1,179 +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 com.alipay.sofa.rpc.metrics.lookout; - -import com.alipay.lookout.api.Id; -import com.alipay.lookout.api.Lookout; -import com.alipay.sofa.rpc.config.ServerConfig; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * @author LiWei.Liangen - */ -public class RpcLookoutId { - - private final ConcurrentMap consumerIds = new ConcurrentHashMap(); - - private final ConcurrentMap providerIds = new ConcurrentHashMap(); - - private final ConcurrentMap serverConfigIds = new ConcurrentHashMap(); - - private volatile Id consumerConfigId; - - private volatile Id providerConfigId; - - private static final Lock classLock = new ReentrantLock(); - private final Lock consumerConfigIdLock = new ReentrantLock(); - private final Lock providerConfigIdLock = new ReentrantLock(); - - /** - * create consumerId - * - * @return consumerId - */ - public Id fetchConsumerStatId(Map tags) { - - String key = tags.toString(); - Id lookoutId = consumerIds.get(key); - if (lookoutId == null) { - classLock.lock(); - try { - lookoutId = consumerIds.get(key); - if (lookoutId == null) { - lookoutId = Lookout.registry().createId("rpc.consumer.service.stats", tags); - consumerIds.put(key, lookoutId); - } - } finally { - classLock.unlock(); - } - } - return lookoutId; - } - - /** - * Create ProviderId - * - * @return ProviderId - */ - public Id fetchProviderStatId(Map tags) { - String key = tags.toString(); - Id lookoutId = providerIds.get(key); - if (lookoutId == null) { - classLock.lock(); - try { - lookoutId = providerIds.get(key); - if (lookoutId == null) { - lookoutId = Lookout.registry().createId("rpc.provider.service.stats", tags); - providerIds.put(key, lookoutId); - } - } finally { - classLock.unlock(); - } - } - return lookoutId; - } - - public Id fetchConsumerSubId() { - if (consumerConfigId == null) { - consumerConfigIdLock.lock(); - try { - if (consumerConfigId == null) { - consumerConfigId = Lookout.registry().createId("rpc.consumer.info.stats"); - } - } finally { - consumerConfigIdLock.unlock(); - } - } - return consumerConfigId; - } - - public Id fetchProviderPubId() { - if (providerConfigId == null) { - providerConfigIdLock.lock(); - try { - if (providerConfigId == null) { - providerConfigId = Lookout.registry().createId("rpc.provider.info.stats"); - } - } finally { - providerConfigIdLock.unlock(); - } - } - return providerConfigId; - } - - public synchronized Id fetchServerThreadConfigId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.config"; - return fetchServerConfigId(key); - } - - public Id fetchServerThreadPoolActiveCountId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.active.count"; - return fetchServerConfigId(key); - } - - public Id fetchServerThreadPoolIdleCountId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.idle.count"; - return fetchServerConfigId(key); - } - - public Id fetchServerThreadPoolQueueSizeId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.queue.size"; - return fetchServerConfigId(key); - } - - private Id fetchServerConfigId(String key) { - Id lookoutId = serverConfigIds.get(key); - if (lookoutId == null) { - classLock.lock(); - try { - lookoutId = serverConfigIds.get(key); - if (lookoutId == null) { - lookoutId = Lookout.registry().createId(key); - serverConfigIds.put(key, lookoutId); - } - } finally { - classLock.unlock(); - } - } - return lookoutId; - } - - public Id removeServerThreadConfigId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.config"; - return serverConfigIds.remove(key); - } - - public Id removeServerThreadPoolActiveCountId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.active.count"; - return serverConfigIds.remove(key); - } - - public Id removeServerThreadPoolIdleCountId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.idle.count"; - return serverConfigIds.remove(key); - } - - public Id removeServerThreadPoolQueueSizeId(ServerConfig serverConfig) { - String key = "rpc." + serverConfig.getProtocol() + ".threadpool.queue.size"; - return serverConfigIds.remove(key); - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcServerLookoutModel.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcServerLookoutModel.java deleted file mode 100644 index db29dacc7..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/metrics/lookout/RpcServerLookoutModel.java +++ /dev/null @@ -1,59 +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 com.alipay.sofa.rpc.metrics.lookout; - -/** - * The model for lookout info of server - * - * @author LiWei.Liangen - */ -public class RpcServerLookoutModel extends RpcAbstractLookoutModel { - - protected String callerApp; - - /** - * Getter method for property callerApp. - * - * @return property value of callerApp - */ - public String getCallerApp() { - return callerApp; - } - - /** - * Setter method for property callerApp. - * - * @param callerApp value to be assigned to property callerApp - */ - public void setCallerApp(String callerApp) { - this.callerApp = callerApp; - } - - @Override - public String toString() { - return "RpcServerLookoutModel{" + - "callerApp='" + callerApp + '\'' + - ", app='" + app + '\'' + - ", service='" + service + '\'' + - ", method='" + method + '\'' + - ", protocol='" + protocol + '\'' + - ", invokeType='" + invokeType + '\'' + - ", elapsedTime=" + elapsedTime + - ", success=" + success + - '}'; - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/module/LookoutModule.java b/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/module/LookoutModule.java deleted file mode 100644 index a1ed9ed93..000000000 --- a/metrics/metrics-lookout/src/main/java/com/alipay/sofa/rpc/module/LookoutModule.java +++ /dev/null @@ -1,71 +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 com.alipay.sofa.rpc.module; - -import com.alipay.sofa.rpc.event.ClientEndInvokeEvent; -import com.alipay.sofa.rpc.event.ConsumerSubEvent; -import com.alipay.sofa.rpc.event.EventBus; -import com.alipay.sofa.rpc.event.LookoutSubscriber; -import com.alipay.sofa.rpc.event.ProviderPubEvent; -import com.alipay.sofa.rpc.event.ServerSendEvent; -import com.alipay.sofa.rpc.event.ServerStartedEvent; -import com.alipay.sofa.rpc.event.ServerStoppedEvent; -import com.alipay.sofa.rpc.ext.Extension; - -/** - * - * @author LiWei.Liangen - */ -@Extension("lookout") -public class LookoutModule implements Module { - - private LookoutSubscriber subscriber; - - @Override - public boolean needLoad() { - try { - Class.forName("com.alipay.lookout.spi.MetricsImporterLocator"); - return true; - } catch (Exception e) { - return false; - } - } - - @Override - public void install() { - subscriber = new LookoutSubscriber(); - EventBus.register(ClientEndInvokeEvent.class, subscriber); - EventBus.register(ServerSendEvent.class, subscriber); - EventBus.register(ServerStartedEvent.class, subscriber); - EventBus.register(ServerStoppedEvent.class, subscriber); - EventBus.register(ProviderPubEvent.class, subscriber); - EventBus.register(ConsumerSubEvent.class, subscriber); - - } - - @Override - public void uninstall() { - if (subscriber != null) { - EventBus.unRegister(ClientEndInvokeEvent.class, subscriber); - EventBus.unRegister(ServerSendEvent.class, subscriber); - EventBus.unRegister(ServerStartedEvent.class, subscriber); - EventBus.unRegister(ServerStoppedEvent.class, subscriber); - EventBus.unRegister(ProviderPubEvent.class, subscriber); - EventBus.unRegister(ConsumerSubEvent.class, subscriber); - } - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.module.Module b/metrics/metrics-lookout/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.module.Module deleted file mode 100644 index 35bb4542d..000000000 --- a/metrics/metrics-lookout/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.module.Module +++ /dev/null @@ -1 +0,0 @@ -lookout=com.alipay.sofa.rpc.module.LookoutModule \ No newline at end of file diff --git a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ConsumerSubTest.java b/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ConsumerSubTest.java deleted file mode 100644 index 9d4bcc0ce..000000000 --- a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ConsumerSubTest.java +++ /dev/null @@ -1,71 +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 com.alipay.sofa.rpc.module; - -import com.alipay.lookout.api.Lookout; -import com.alipay.lookout.api.NoopRegistry; -import com.alipay.lookout.api.Registry; -import com.alipay.lookout.core.DefaultRegistry; -import com.alipay.lookout.core.InfoWrapper; -import com.alipay.sofa.rpc.config.ConsumerConfig; -import com.alipay.sofa.rpc.event.ConsumerSubEvent; -import com.alipay.sofa.rpc.event.EventBus; -import com.alipay.sofa.rpc.metrics.lookout.RpcLookoutId; -import org.junit.Assert; -import org.junit.Test; - -import java.util.concurrent.TimeUnit; - -/** - * @author zhiyuan.lzy - */ -public class ConsumerSubTest { - - @Test - public void testSubLookout() { - - Registry registry = new DefaultRegistry(); - - if (Lookout.registry() == NoopRegistry.INSTANCE) { - Lookout.setRegistry(registry); - } - - LookoutModule lookoutModule = new LookoutModule(); - Assert.assertEquals(true, lookoutModule.needLoad()); - - lookoutModule.install(); - ConsumerConfig consumerConfig = new ConsumerConfig(); - consumerConfig.setInterfaceId("a"); - EventBus.post(new ConsumerSubEvent(consumerConfig)); - - try { - TimeUnit.SECONDS.sleep(5); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - RpcLookoutId rpcLookoutId = new RpcLookoutId(); - InfoWrapper result = Lookout.registry().get(rpcLookoutId.fetchConsumerSubId()); - final Object value = result.value(); - Assert.assertTrue(value instanceof ConsumerConfig); - - consumerConfig = (ConsumerConfig) value; - - Assert.assertEquals("a", consumerConfig.getInterfaceId()); - } - -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/LookoutModuleTest.java b/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/LookoutModuleTest.java deleted file mode 100644 index 6c2399622..000000000 --- a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/LookoutModuleTest.java +++ /dev/null @@ -1,33 +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 com.alipay.sofa.rpc.module; - -import org.junit.Assert; -import org.junit.Test; - -/** - * - * @author LiWei.Liangen - */ -public class LookoutModuleTest { - - @Test - public void testNeedLoad() { - LookoutModule lookoutModule = new LookoutModule(); - Assert.assertEquals(true, lookoutModule.needLoad()); - } -} \ No newline at end of file diff --git a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ProviderPubTest.java b/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ProviderPubTest.java deleted file mode 100644 index dc50469dc..000000000 --- a/metrics/metrics-lookout/src/test/java/com/alipay/sofa/rpc/module/ProviderPubTest.java +++ /dev/null @@ -1,68 +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 com.alipay.sofa.rpc.module; - -import com.alipay.lookout.api.Lookout; -import com.alipay.lookout.api.NoopRegistry; -import com.alipay.lookout.api.Registry; -import com.alipay.lookout.core.DefaultRegistry; -import com.alipay.lookout.core.InfoWrapper; -import com.alipay.sofa.rpc.config.ProviderConfig; -import com.alipay.sofa.rpc.event.EventBus; -import com.alipay.sofa.rpc.event.ProviderPubEvent; -import com.alipay.sofa.rpc.metrics.lookout.RpcLookoutId; -import org.junit.Assert; -import org.junit.Test; - -import java.util.concurrent.TimeUnit; - -/** - * @author zhiyuan.lzy - */ -public class ProviderPubTest { - - @Test - public void testPubLookout() { - - Registry registry = new DefaultRegistry(); - if (Lookout.registry() == NoopRegistry.INSTANCE) { - Lookout.setRegistry(registry); - } - LookoutModule lookoutModule = new LookoutModule(); - Assert.assertEquals(true, lookoutModule.needLoad()); - - lookoutModule.install(); - ProviderConfig providerConfig = new ProviderConfig(); - providerConfig.setInterfaceId("a"); - EventBus.post(new ProviderPubEvent(providerConfig)); - - try { - TimeUnit.SECONDS.sleep(5); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - RpcLookoutId rpcLookoutId = new RpcLookoutId(); - InfoWrapper result = Lookout.registry().get(rpcLookoutId.fetchProviderPubId()); - final Object value = result.value(); - Assert.assertTrue(value instanceof ProviderConfig); - - providerConfig = (ProviderConfig) value; - - Assert.assertEquals("a", providerConfig.getInterfaceId()); - } -} \ No newline at end of file diff --git a/metrics/pom.xml b/metrics/pom.xml index e50d83a16..b960206d4 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -14,7 +14,6 @@ pom - metrics-lookout metrics-micrometer metrics-prometheus diff --git a/registry/registry-sofa/pom.xml b/registry/registry-sofa/pom.xml index f1427cb07..122db11bc 100644 --- a/registry/registry-sofa/pom.xml +++ b/registry/registry-sofa/pom.xml @@ -47,11 +47,6 @@ commons-pool - - com.alipay.sofa.lookout - lookout-api - - com.alipay.sofa registry-test diff --git a/test/test-integration/pom.xml b/test/test-integration/pom.xml index 5d78a8e48..87aef8ddc 100644 --- a/test/test-integration/pom.xml +++ b/test/test-integration/pom.xml @@ -131,11 +131,6 @@ sofa-rpc-log-common-tools ${project.parent.version} - - com.alipay.sofa - sofa-rpc-metrics-lookout - ${project.parent.version} - com.alipay.sofa sofa-rpc-metrics-micrometer @@ -256,13 +251,6 @@ - - - com.alipay.sofa.lookout - lookout-core - test - - org.slf4j slf4j-log4j12 diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutService.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutService.java deleted file mode 100644 index c3501e83a..000000000 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutService.java +++ /dev/null @@ -1,33 +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 com.alipay.sofa.rpc.metrics.lookout; - -/** - * - * @author LiWei.Liangen - */ -public interface LookoutService { - - String saySync(String string) throws InterruptedException; - - String sayFuture(String string) throws InterruptedException; - - String sayCallback(String string) throws InterruptedException; - - String sayOneway(String string) throws InterruptedException; - -} \ No newline at end of file diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutServiceImpl.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutServiceImpl.java deleted file mode 100644 index 1a51743b7..000000000 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/LookoutServiceImpl.java +++ /dev/null @@ -1,72 +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 com.alipay.sofa.rpc.metrics.lookout; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * - * @author LiWei.Liangen - */ -public class LookoutServiceImpl implements LookoutService { - - private final AtomicInteger countSync = new AtomicInteger(); - private final AtomicInteger countFuture = new AtomicInteger(); - private final AtomicInteger countCallback = new AtomicInteger(); - private final AtomicInteger countOneway = new AtomicInteger(); - - @Override - public String saySync(String string) throws InterruptedException { - if (countSync.incrementAndGet() == 3) { - Thread.sleep(3500); - throw new RuntimeException(); - } else { - return string; - } - } - - @Override - public String sayFuture(String string) throws InterruptedException { - if (countFuture.incrementAndGet() == 4) { - Thread.sleep(3500); - throw new RuntimeException(); - } else { - return string; - } - } - - @Override - public String sayCallback(String string) throws InterruptedException { - if (countCallback.incrementAndGet() == 5) { - Thread.sleep(3500); - throw new RuntimeException(); - } else { - return string; - } - } - - @Override - public String sayOneway(String string) throws InterruptedException { - if (countOneway.incrementAndGet() == 6) { - Thread.sleep(3500); - throw new RuntimeException(); - } else { - return string; - } - } - -} \ No newline at end of file diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutTest.java deleted file mode 100644 index 901da949a..000000000 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/metrics/lookout/RpcLookoutTest.java +++ /dev/null @@ -1,637 +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 com.alipay.sofa.rpc.metrics.lookout; - -import com.alipay.lookout.api.Id; -import com.alipay.lookout.api.Lookout; -import com.alipay.lookout.api.Measurement; -import com.alipay.lookout.api.Metric; -import com.alipay.lookout.api.NoopRegistry; -import com.alipay.lookout.api.Registry; -import com.alipay.lookout.api.Tag; -import com.alipay.lookout.core.DefaultRegistry; -import com.alipay.sofa.rpc.api.future.SofaResponseFuture; -import com.alipay.sofa.rpc.common.RpcConstants; -import com.alipay.sofa.rpc.common.utils.StringUtils; -import com.alipay.sofa.rpc.config.ApplicationConfig; -import com.alipay.sofa.rpc.config.ConsumerConfig; -import com.alipay.sofa.rpc.config.MethodConfig; -import com.alipay.sofa.rpc.config.ProviderConfig; -import com.alipay.sofa.rpc.config.ServerConfig; -import com.alipay.sofa.rpc.context.RpcRunningState; -import com.alipay.sofa.rpc.core.exception.SofaRpcException; -import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback; -import com.alipay.sofa.rpc.core.request.RequestBase; -import com.alipay.sofa.rpc.test.ActivelyDestroyTest; -import java.util.Iterator; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * @author LiWei.Liangen - */ -public class RpcLookoutTest extends ActivelyDestroyTest { - - static Field corePoolSize; - static Field maxPoolSize; - static Field queueSize; - - private ServerConfig serverConfig; - - private ProviderConfig providerConfig; - - private ConsumerConfig consumerConfig; - - private LookoutService lookoutService; - - private CountSofaResponseCallback onReturn; - - @BeforeClass - public static void beforeClass() { - - RpcRunningState.setUnitTestMode(false); - - try { - Class clazz = RpcLookout.class; - Class[] innerClazzs = clazz.getDeclaredClasses(); - for (Class cls : innerClazzs) { - if (cls.getName().contains("ThreadPoolConfig")) { - corePoolSize = cls.getDeclaredField("corePoolSize"); - corePoolSize.setAccessible(true); - - maxPoolSize = cls.getDeclaredField("maxPoolSize"); - maxPoolSize.setAccessible(true); - - queueSize = cls.getDeclaredField("queueSize"); - queueSize.setAccessible(true); - } - } - } catch (Exception e) { - LOGGER.error("", e); - } - - Registry registry = new DefaultRegistry(); - final Registry currentRegistry = Lookout.registry(); - if (currentRegistry == NoopRegistry.INSTANCE) { - Lookout.setRegistry(registry); - } else { - //clear all metrics now - Iterator itar = currentRegistry.iterator(); - while (itar.hasNext()) { - Metric metric = itar.next(); - Id id = metric.id(); - currentRegistry.removeMetric(id); - - } - } - } - - @AfterClass - public static void adAfterClass() { - RpcRunningState.setUnitTestMode(true); - ActivelyDestroyTest.adAfterClass(); - } - - private Metric fetchWithNameAndMethod(String name, String methodName) { - Registry registry = Lookout.registry(); - for (Metric metric : registry) { - LOGGER.info("metrics name is " + metric.id() + ",name=" + name + ",methodName=" + methodName); - if (metric.id().name().equalsIgnoreCase(name)) { - if (StringUtils.isEmpty(methodName)) { - return metric; - } - if (matchTagFromMetrics(metric, methodName)) { - return metric; - } - } - } - return null; - } - - /** - * invoke - */ - @Before - public void before() { - - final Registry currentRegistry = Lookout.registry(); - //clear all metrics now - Iterator itar = currentRegistry.iterator(); - while (itar.hasNext()) { - Metric metric = itar.next(); - Id id = metric.id(); - currentRegistry.removeMetric(id); - } - - serverConfig = new ServerConfig() - .setPort(12201) - .setCoreThreads(30) - .setMaxThreads(500) - .setQueues(600) - .setProtocol(RpcConstants.PROTOCOL_TYPE_BOLT); - - providerConfig = new ProviderConfig() - .setInterfaceId(LookoutService.class.getName()) - .setRef(new LookoutServiceImpl()) - .setServer(serverConfig) - .setBootstrap("bolt") - .setRegister(false) - .setApplication(new ApplicationConfig().setAppName("TestLookOutServer")); - providerConfig.export(); - - MethodConfig methodConfigFuture = new MethodConfig() - .setName("sayFuture") - .setInvokeType("future"); - onReturn = new CountSofaResponseCallback(); - MethodConfig methodConfigCallback = new MethodConfig() - .setName("sayCallback") - .setInvokeType("callback") - .setOnReturn(onReturn); - MethodConfig methodConfigOneway = new MethodConfig() - .setName("sayOneway") - .setInvokeType("oneway"); - List methodConfigs = new ArrayList(); - methodConfigs.add(methodConfigFuture); - methodConfigs.add(methodConfigCallback); - methodConfigs.add(methodConfigOneway); - - consumerConfig = new ConsumerConfig() - .setInterfaceId(LookoutService.class.getName()) - .setProtocol("bolt") - .setBootstrap("bolt") - .setMethods(methodConfigs) - .setTimeout(3000) - .setRegister(false) - .setDirectUrl("bolt://127.0.0.1:12201?appName=TestLookOutServer") - .setApplication(new ApplicationConfig().setAppName("TestLookOutClient")); - lookoutService = consumerConfig.refer(); - - } - - @After - public void after() { - - final Registry currentRegistry = Lookout.registry(); - //clear all metrics now - Iterator itar = currentRegistry.iterator(); - while (itar.hasNext()) { - Metric metric = itar.next(); - Id id = metric.id(); - currentRegistry.removeMetric(id); - } - - if (serverConfig != null) { - serverConfig.destroy(); - } - if (providerConfig != null) { - providerConfig.unExport(); - } - if (consumerConfig != null) { - consumerConfig.unRefer(); - } - } - - /** - * test thread pool config - * - * @throws Exception Exception - */ - @Test - public void testThreadPoolConfig() throws Exception { - - Metric metric = fetchWithNameAndMethod("rpc.bolt.threadpool.config", ""); - - Collection measurements = metric.measure().measurements(); - assertTrue(measurements.size() == 1); - for (Measurement measurement : measurements) { - - // 判断ThreadPool启动配置 - Object obj = measurement.value(); - - assertEquals(30, corePoolSize.get(obj)); - assertEquals(500, maxPoolSize.get(obj)); - assertEquals(600, queueSize.get(obj)); - } - } - - /** - * test thread pool active count - * - * @throws Exception Exception - */ - @Test - public void testThreadPoolActiveCount() throws Exception { - - Metric metric = fetchWithNameAndMethod("rpc.bolt.threadpool.active.count", ""); - - Collection measurements = metric.measure().measurements(); - assertTrue(measurements.size() == 1); - for (Measurement measurement : measurements) { - assertEquals(0, ((Number) measurement.value()).intValue()); - } - } - - /** - * test thread pool idle count - */ - @Test - public void testThreadPoolIdleCount() { - - //sync invoke some time - for (int i = 0; i < 3; i++) { - try { - lookoutService.saySync("lookout_sync"); - } catch (Exception e) { - LOGGER.error("sync error", e); - } - } - - try { - TimeUnit.SECONDS.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - Metric metric = fetchWithNameAndMethod("rpc.bolt.threadpool.idle.count", ""); - - Collection measurements = metric.measure().measurements(); - assertTrue(measurements.size() == 1); - for (Measurement measurement : measurements) { - assertEquals(3, ((Number) measurement.value()).intValue()); - } - } - - /** - * test thread pool queue size - */ - @Test - public void testThreadPoolQueueSize() { - - Metric metric = fetchWithNameAndMethod("rpc.bolt.threadpool.queue.size", ""); - - Collection measurements = metric.measure().measurements(); - assertTrue(measurements.size() == 1); - for (Measurement measurement : measurements) { - assertEquals(0, ((Number) measurement.value()).intValue()); - } - } - - /** - * test provider service stats - */ - @Test - public void testFutureServiceStats() { - - //future - for (int i = 0; i < 4; i++) { - try { - lookoutService.sayFuture("lookout_future"); - SofaResponseFuture.getResponse(3000, true); - } catch (Exception e) { - LOGGER.error("future error", e); - } - } - - try { - TimeUnit.SECONDS.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - String methodName = "sayFuture"; - Metric metric = fetchWithNameAndMethod("rpc.provider.service.stats", methodName); - if (metric == null) { - Assert.fail("no provider metric was found null"); - } - assertMethod(metric, true, 4, methodName, 0, 0); - - Metric consumerMetric = fetchWithNameAndMethod("rpc.consumer.service.stats", methodName); - - if (consumerMetric == null) { - Assert.fail("no consumer metric was found null"); - } - - assertMethod(consumerMetric, false, 4, methodName, 1620, 534); - - } - - /** - * test provider service stats - */ - @Test - public void testCallbackServiceStats() { - - //callback - for (int i = 0; i < 5; i++) { - try { - lookoutService.sayCallback("lookout_callback"); - } catch (Exception e) { - LOGGER.error("callback error", e); - } - } - - for (int i = 0; i < 10; i++) { - try { - TimeUnit.SECONDS.sleep(3); - } catch (InterruptedException e) { - } - if (onReturn.getSize() == 5) { - break; - } - } - String methodName = "sayCallback"; - - Metric metric = fetchWithNameAndMethod("rpc.provider.service.stats", methodName); - - if (metric == null) { - Assert.fail("no provider metric was found null"); - } - - assertMethod(metric, true, 5, methodName, 0, 0); - - Metric consumerMetric = fetchWithNameAndMethod("rpc.consumer.service.stats", methodName); - - if (consumerMetric == null) { - Assert.fail("no consumer eetric was found null"); - } - - assertMethod(consumerMetric, false, 5, methodName, 2045, 720); - - } - - /** - * test provider service stats - */ - @Test - public void testOnewayServiceStats() { - - //oneway - for (int i = 0; i < 6; i++) { - try { - lookoutService.sayOneway("lookout_oneway"); - } catch (Exception e) { - LOGGER.error("oneway error", e); - } - } - - try { - TimeUnit.SECONDS.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - String methodName = "sayOneway"; - Metric metric = fetchWithNameAndMethod("rpc.provider.service.stats", methodName); - - if (metric == null) { - Assert.fail("no provider metric was found null"); - } - - assertMethod(metric, true, 6, methodName, 0, 0); - - Metric consumerMetric = fetchWithNameAndMethod("rpc.consumer.service.stats", methodName); - - if (consumerMetric == null) { - Assert.fail("no consumer metric was found null"); - } - - assertMethod(consumerMetric, false, 6, methodName, 2430, 0); - - } - - /** - * test provider service stats - */ - @Test - public void testSyncServiceStats() { - System.out.println("start where is the log"); - - //sync - for (int i = 0; i < 3; i++) { - try { - lookoutService.saySync("lookout_sync"); - System.out.println("lookout_sync invoke success"); - } catch (Exception e) { - LOGGER.error("sync error", e); - } - } - - try { - TimeUnit.SECONDS.sleep(10); - } catch (InterruptedException e) { - LOGGER.error("wait InterruptedException", e); - } - String methodName = "saySync"; - Metric metric = fetchWithNameAndMethod("rpc.provider.service.stats", methodName); - Assert.assertNotEquals("metrics is null", null, metric); - - if (metric == null) { - Assert.fail("no provider metric was found null"); - } - assertMethod(metric, true, 3, methodName, 0, 0); - - Metric consumerMetric = fetchWithNameAndMethod("rpc.consumer.service.stats", methodName); - if (consumerMetric == null) { - Assert.fail("no consumer metric was found null"); - } - - assertMethod(consumerMetric, false, 3, methodName, 1203, 352); - - } - - /** - * 通过methodName获取 - * - * @param metric - * @param methodName - * @return - */ - private boolean matchTagFromMetrics(Metric metric, String methodName) { - for (Tag tag : metric.id().tags()) { - if (tag.key().equalsIgnoreCase("method")) { - String value = tag.value(); - if (StringUtils.equals(methodName, value)) { - return true; - } - } - } - return false; - } - - /** - * assert method - * - * @param metric the metric - * @param isProvider is it the provider - * @param totalCount the total invoke count - * @param method the method name - * @param requestSize the request size - * @param responseSize the response size - */ - private void assertMethod(Metric metric, boolean isProvider, int totalCount, String method, int requestSize, - int responseSize) { - // tag - boolean tagAssert = false; - for (Tag tag : metric.id().tags()) { - String key = tag.key(); - String value = tag.value(); - LOGGER.info(this.getClass().getName() + ",key=" + key + ",value=" + value); - if (key.equals("service")) { - assertEquals("service not equal", LookoutService.class.getCanonicalName() + ":1.0", value); - tagAssert = true; - } - if (key.equals("protocol")) { - assertEquals("protocol not equal", "bolt", value); - tagAssert = true; - } - if (key.equals("method")) { - assertEquals("method not equal", method, value); - tagAssert = true; - } - if (isProvider) { - if (key.equals("app")) { - assertEquals("app not equal in provider", "TestLookOutServer", value); - tagAssert = true; - } - if (key.equals("caller_app")) { - assertEquals("caller_app not equal in provider", "TestLookOutClient", value); - tagAssert = true; - } - } else { - if (key.equals("app")) { - assertEquals("app not equal in consumer", "TestLookOutClient", value); - tagAssert = true; - } - if (key.equals("target_app")) { - assertEquals("target_app not equal in consumer", "TestLookOutServer", value); - tagAssert = true; - } - if (key.equals("invoke_type")) { - assertEquals("invoke_type not equal in consumer", method.substring(3).toLowerCase(), value); - - } - } - } - if (!tagAssert) { - Assert.fail("tag assert not executed"); - } - - // invoke info - Collection measurements = metric.measure().measurements(); - if (isProvider) { - assertEquals("measurements size is not equal", 6, measurements.size()); - } else { - if (method.equals("sayOneway")) { - assertEquals("measurements is not equal in sayOneway", 5, measurements.size()); - } else { - assertEquals("measurements is not equal in others", 10, measurements.size()); - } - } - - boolean invokeInfoAssert = false; - for (Measurement measurement : measurements) { - - String name = measurement.name(); - int value = ((Long) measurement.value()).intValue(); - - LOGGER.info(this.getClass().getName() + ",name=" + name + ",value=" + value); - - if (name.equals("total_count")) { - assertEquals("total_count is not equal", totalCount, value); - invokeInfoAssert = true; - } - if (name.equals("total_time.totalTime")) { - if (method.equals("sayOneway") && !isProvider) { - assertTrue("totalTime is not equal in consumer", value < 3000); - } else { - assertTrue("totalTime is not equal in provider", value > 3000); - } - invokeInfoAssert = true; - } - if (name.equals("total_time.count")) { - assertEquals("count is not equal", totalCount, value); - invokeInfoAssert = true; - } - if (name.equals("fail_count")) { - assertEquals("fail_count is not equal", 1, value); - invokeInfoAssert = true; - } - if (name.equals("fail_time.totalTime")) { - assertTrue("fail_time.totalTime is not equal", value > 3000); - invokeInfoAssert = true; - } - if (name.equals("fail_time.count")) { - assertEquals("fail_time.count is not equal", 1, value); - invokeInfoAssert = true; - } - if (!isProvider) { - if (name.equals("request_size.count")) { - LOGGER.info("request_size.count,value={},requestSize={},totalCount={}", value, requestSize, - totalCount); - assertTrue("request_size.count is smaller than 0", requestSize > 0); - invokeInfoAssert = true; - } - if (name.equals("response_size.count")) { - LOGGER.info("response_size.count,value={},responseSize={},totalCount={}", value, responseSize, - totalCount); - assertTrue("response_size.count is smaller than 0", responseSize > 0); - invokeInfoAssert = true; - } - } - } - if (!invokeInfoAssert) { - Assert.fail("invoke assert not executed"); - } - } - - public static class CountSofaResponseCallback implements SofaResponseCallback { - private int size = 0; - - @Override - public void onAppResponse(Object appResponse, String methodName, RequestBase request) { - size++; - } - - @Override - public void onAppException(Throwable throwable, String methodName, RequestBase request) { - size++; - } - - @Override - public void onSofaException(SofaRpcException sofaException, String methodName, - RequestBase request) { - size++; - } - - public int getSize() { - return size; - } - } -} \ No newline at end of file diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/server/rest/RestLookoutTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/server/rest/RestLookoutTest.java deleted file mode 100644 index 62c051623..000000000 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/server/rest/RestLookoutTest.java +++ /dev/null @@ -1,354 +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 com.alipay.sofa.rpc.server.rest; - -import com.alipay.lookout.api.Id; -import com.alipay.lookout.api.Lookout; -import com.alipay.lookout.api.Measurement; -import com.alipay.lookout.api.Metric; -import com.alipay.lookout.api.NoopRegistry; -import com.alipay.lookout.api.Registry; -import com.alipay.lookout.api.Tag; -import com.alipay.lookout.core.DefaultRegistry; -import com.alipay.sofa.rpc.common.RpcConstants; -import com.alipay.sofa.rpc.common.utils.StringUtils; -import com.alipay.sofa.rpc.config.ApplicationConfig; -import com.alipay.sofa.rpc.config.ConsumerConfig; -import com.alipay.sofa.rpc.config.JAXRSProviderManager; -import com.alipay.sofa.rpc.config.ProviderConfig; -import com.alipay.sofa.rpc.config.ServerConfig; -import com.alipay.sofa.rpc.context.RpcRunningState; -import com.alipay.sofa.rpc.context.RpcRuntimeContext; -import com.alipay.sofa.rpc.test.ActivelyDestroyTest; -import java.util.Iterator; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.util.Collection; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * @author LiWei.Liangen - */ -public class RestLookoutTest extends ActivelyDestroyTest { - - private ServerConfig serverConfig; - - private ProviderConfig providerConfig; - - private ConsumerConfig consumerConfig; - - private RestService helloService; - - private Metric fetchWithNameAndMethod(String name, String methodName) { - Registry registry = Lookout.registry(); - for (Metric metric : registry) { - LOGGER.info("metrics name is " + metric.id() + ",name=" + name + ",methodName=" + methodName); - if (metric.id().name().equalsIgnoreCase(name)) { - - if (StringUtils.isEmpty(methodName)) { - return metric; - } - if (matchTagFromMetrics(metric, methodName)) { - return metric; - } - } - } - return null; - } - - /** - * 通过methodName获取 - * - * @param metric - * @param methodName - * @return - */ - private boolean matchTagFromMetrics(Metric metric, String methodName) { - for (Tag tag : metric.id().tags()) { - if (tag.key().equalsIgnoreCase("method")) { - String value = tag.value(); - if (StringUtils.equals(methodName, value)) { - return true; - } - } - } - return false; - } - - @BeforeClass - public static void beforeCurrentClass() { - - RpcRunningState.setUnitTestMode(false); - - JAXRSProviderManager.registerInternalProviderClass(LookoutRequestFilter.class); - - RpcRuntimeContext.putIfAbsent(RpcRuntimeContext.KEY_APPNAME, "TestLookOutServer"); - - Registry registry = new DefaultRegistry(); - final Registry currentRegistry = Lookout.registry(); - if (currentRegistry == NoopRegistry.INSTANCE) { - Lookout.setRegistry(registry); - } else { - //clear all metrics now - Iterator itar = currentRegistry.iterator(); - while (itar.hasNext()) { - Metric metric = itar.next(); - Id id = metric.id(); - currentRegistry.removeMetric(id); - } - } - } - - @AfterClass - public static void afterCurrentClass() { - - JAXRSProviderManager.removeInternalProviderClass(LookoutRequestFilter.class); - - RpcRunningState.setUnitTestMode(true); - ActivelyDestroyTest.adAfterClass(); - } - - /** - * invoke - */ - @Before - public void beforeMethod() { - - // 只有1个线程 执行 - serverConfig = new ServerConfig() - .setStopTimeout(1000) - .setPort(8802) - .setProtocol(RpcConstants.PROTOCOL_TYPE_REST) - .setContextPath("/xyz"); - //.setQueues(100).setCoreThreads(1).setMaxThreads(2); - - // 发布一个服务,每个请求要执行1秒 - ApplicationConfig serverApplication = new ApplicationConfig(); - serverApplication.setAppName("TestLookOutServer"); - providerConfig = new ProviderConfig() - .setInterfaceId(RestService.class.getName()) - .setRef(new RestServiceImpl()) - .setServer(serverConfig) - .setBootstrap("rest") - //.setParameter(RpcConstants.CONFIG_HIDDEN_KEY_WARNING, "false") - .setRegister(false) - .setApplication(serverApplication); - providerConfig.export(); - - ApplicationConfig clientApplication = new ApplicationConfig(); - clientApplication.setAppName("TestLookOutClient"); - consumerConfig = new ConsumerConfig() - .setInterfaceId(RestService.class.getName()) - .setDirectUrl( - "rest://127.0.0.1:8802/xyz?uniqueId=&version=1" - + ".0&timeout=0&delay=-1&id=rpc-cfg-0&dynamic=true&weight=100&accepts=100000" - + "&startTime=1523240755024&appName=" - + - serverApplication.getAppName() + "&pid=22385&language=java&rpcVer=50300") - .setProtocol("rest") - .setBootstrap("rest") - .setTimeout(30000) - .setConnectionNum(5) - .setRegister(false) - .setApplication(clientApplication); - helloService = consumerConfig.refer(); - - } - - @After - public void afterMethod() { - - //clear all metrics now - Registry currentRegistry = Lookout.registry(); - Iterator itar = currentRegistry.iterator(); - while (itar.hasNext()) { - Metric metric = itar.next(); - Id id = metric.id(); - currentRegistry.removeMetric(id); - } - - if (providerConfig != null) { - providerConfig.unExport(); - } - if (consumerConfig != null) { - consumerConfig.unRefer(); - } - if (serverConfig != null) { - serverConfig.destroy(); - } - - } - - /** - * test provider service stats - */ - @Test - public void testServiceStats() { - - Assert.assertEquals(helloService.query(11), "hello world !null"); - - //wait metrics info - try { - TimeUnit.SECONDS.sleep(5); - } catch (InterruptedException e) { - e.printStackTrace(); - } - String methodName = "query"; - - Metric metric = fetchWithNameAndMethod("rpc.provider.service.stats", methodName); - if (metric == null) { - Assert.fail("no provider metric was found null"); - } - - assertMethod(metric, true, 1, methodName, 0, 0); - - //metrics for consumer - Metric consumerMetric = fetchWithNameAndMethod("rpc.consumer.service.stats", methodName); - if (consumerMetric == null) { - Assert.fail("no consumer metric was found null"); - } - - assertMethod(consumerMetric, false, 1, methodName, 1203, 352); - - } - - /** - * assert method - * - * @param metric the metric - * @param isProvider is it the provider - * @param totalCount the total invoke count - * @param method the method name - * @param requestSize the request size - * @param responseSize the response size - */ - private void assertMethod(Metric metric, boolean isProvider, int totalCount, String method, int requestSize, - int responseSize) { - // tag - boolean tagAssert = false; - for (Tag tag : metric.id().tags()) { - - String key = tag.key(); - String value = tag.value(); - LOGGER.info(this.getClass().getName() + ",key=" + key + ",value=" + value); - if (key.equals("service")) { - assertEquals("service not equal", RestService.class.getCanonicalName() + ":1.0", value); - tagAssert = true; - } - if (key.equals("protocol")) { - assertEquals("protocol not equal", "rest", value); - tagAssert = true; - } - if (key.equals("method")) { - assertEquals("method not equal", method, value); - tagAssert = true; - } - if (isProvider) { - if (key.equals("app")) { - assertEquals("app not equal in provider", "TestLookOutServer", value); - tagAssert = true; - } - if (key.equals("caller_app")) { - assertEquals("caller_app not equal in provider", "TestLookOutClient", value); - tagAssert = true; - } - } else { - if (key.equals("app")) { - assertEquals("app not equal in consumer", "TestLookOutClient", value); - tagAssert = true; - } - if (key.equals("target_app")) { - assertEquals("target_app not equal in consumer", "TestLookOutServer", value); - tagAssert = true; - } - if (key.equals("invoke_type")) { - assertEquals("invoke_type not equal in consumer", "sync", value); - - } - } - } - if (!tagAssert) { - Assert.fail("no tag assert"); - } - - // invoke info - Collection measurements = metric.measure().measurements(); - if (isProvider) { - assertEquals("measurements is not equals in provider", 3, measurements.size()); - } else { - assertEquals("measurements is not equals in consumer", 4, measurements.size()); - } - - boolean invokeInfoAssert = false; - for (Measurement measurement : measurements) { - String name = measurement.name(); - int value = ((Long) measurement.value()).intValue(); - - LOGGER.info(this.getClass().getName() + ",name=" + name + ",value=" + value); - - if (name.equals("total_count")) { - assertEquals("total_count is not equal", totalCount, value); - invokeInfoAssert = true; - } - if (name.equals("total_time.totalTime")) { - assertTrue("totalTime is not equal", value < 3000); - invokeInfoAssert = true; - } - if (name.equals("total_time.count")) { - assertEquals("count is not equal", totalCount, value); - invokeInfoAssert = true; - } - if (name.equals("fail_count")) { - assertEquals("fail_count is not equal", 1, value); - invokeInfoAssert = true; - } - if (name.equals("fail_time.totalTime")) { - assertTrue("fail_time.totalTime is not equal", value > 3000); - invokeInfoAssert = true; - } - if (name.equals("fail_time.count")) { - assertEquals("fail_time.count is not equal", 1, value); - invokeInfoAssert = true; - } - if (!isProvider) { - if (name.equals("request_size.count")) { - LOGGER.info("request_size.count,value={},requestSize={},totalCount={}", value, requestSize, - totalCount); - assertTrue("request_size.count is smaller than 0", requestSize > 0); - invokeInfoAssert = true; - } - if (name.equals("response_size.count")) { - LOGGER.info("response_size.count,value={},responseSize={},totalCount={}", value, responseSize, - totalCount); - assertTrue("response_size.count is smaller than 0", requestSize > 0); - invokeInfoAssert = true; - } - } - } - if (!invokeInfoAssert) { - Assert.fail("no invoke info assert"); - } - } -} \ No newline at end of file From ab83fc34aa4a6a225742b800a8cbf16a6c090937 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Tue, 8 Oct 2024 15:08:41 +0800 Subject: [PATCH 52/64] feat: support triple grpc heart beat (#1432) * feat: support triple grpc heart beat * fix: key --------- Co-authored-by: Lo1nt --- .../alipay/sofa/rpc/common/RpcOptions.java | 1 + .../sofa/rpc/common/config/RpcConfigKeys.java | 12 +++++++ .../sofa/rpc/common/rpc-config-default.json | 2 ++ .../triple/TripleClientTransport.java | 12 +++++++ .../triple/TripleClientTransportTest.java | 35 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransportTest.java diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java index ff9ebebd3..2abdcdfc8 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcOptions.java @@ -419,6 +419,7 @@ public class RpcOptions { * 默认 grpc maxInboundMessageSize大小 */ public static final String TRANSPORT_GRPC_MAX_INBOUND_MESSAGE_SIZE = "transport.grpc.maxInboundMessageSize"; + /** * 最大IO的buffer大小 */ diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java index 2b4934ce0..d15aae3ac 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java @@ -140,4 +140,16 @@ public class RpcConfigKeys { false, "specify biz thread pool implementation type", new String[] { "sofa_rpc_server_thread_pool_type" }); + + /** + * grpc client keep alive interval + */ + public static ConfigKey TRIPLE_CLIENT_KEEP_ALIVE_INTERVAL = ConfigKey + .build( + "sofa.rpc.triple.client.keepAlive.interval", + 0, + false, + "keep alive interval in second for triple client", + new String[] { "sofa_rpc_triple_client_keepAlive_interval" }); + } diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json index 796594c8f..48aaddf2b 100644 --- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json +++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json @@ -273,6 +273,8 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支 "compress.size.baseline": 2048, //Whether the Http2 Cleartext protocol client uses Prior Knowledge to start Http2 "transport.client.h2c.usePriorKnowledge": true, + // grpc client keep alive interval, default to 0, no keep alive + "sofa.rpc.triple.client.keepAlive.interval": 0, /*-------------Transport层相关配置结束-------------*/ /* diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransport.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransport.java index bf8adbe17..ee8f3e1bc 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransport.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransport.java @@ -16,9 +16,11 @@ */ package com.alipay.sofa.rpc.transport.triple; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.client.ProviderInfo; import com.alipay.sofa.rpc.common.RpcConfigs; import com.alipay.sofa.rpc.common.RpcOptions; +import com.alipay.sofa.rpc.common.config.RpcConfigKeys; import com.alipay.sofa.rpc.common.utils.NetUtils; import com.alipay.sofa.rpc.context.RpcInternalContext; import com.alipay.sofa.rpc.context.RpcInvokeContext; @@ -78,6 +80,10 @@ public class TripleClientTransport extends ClientTransport { protected final Object lock = new Object(); + protected static int KEEP_ALIVE_INTERVAL = SofaConfigs.getOrCustomDefault( + RpcConfigKeys.TRIPLE_CLIENT_KEEP_ALIVE_INTERVAL, + RpcConfigs.getIntValue(RpcConfigKeys.TRIPLE_CLIENT_KEEP_ALIVE_INTERVAL.getKey())); + /** * The constructor * @@ -278,6 +284,12 @@ private ManagedChannel initChannel(ProviderInfo url) { builder.disableRetry(); builder.intercept(clientHeaderClientInterceptor); builder.maxInboundMessageSize(RpcConfigs.getIntValue(RpcOptions.TRANSPORT_GRPC_MAX_INBOUND_MESSAGE_SIZE)); + + if (KEEP_ALIVE_INTERVAL > 0) { + builder.keepAliveWithoutCalls(true); + builder.keepAliveTime(KEEP_ALIVE_INTERVAL, TimeUnit.SECONDS); + } + return builder.build(); } diff --git a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransportTest.java b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransportTest.java new file mode 100644 index 000000000..23ca132d9 --- /dev/null +++ b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/transport/triple/TripleClientTransportTest.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 com.alipay.sofa.rpc.transport.triple; + +import org.junit.Assert; +import org.junit.Test; + +/** + * + * @author junyuan + * @version TripleClientTransportTest.java, v 0.1 2024-08-01 17:12 junyuan Exp $ + */ +public class TripleClientTransportTest { + + @Test + public void testInit() { + + Assert.assertEquals(TripleClientTransport.KEEP_ALIVE_INTERVAL, 0); + + } +} \ No newline at end of file From 715080469388347ff465a1d79e17a0d7055aa8e3 Mon Sep 17 00:00:00 2001 From: Wang Chengming Date: Tue, 8 Oct 2024 16:22:24 +0800 Subject: [PATCH 53/64] fix organization url, the http://www.antfin.com is currently unavailable (#1440) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix organization url --------- Co-authored-by: 呈铭 Co-authored-by: liujianjun.ljj --- all/pom.xml | 16 ++++++++-------- pom.xml | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index b47e12d07..62800ab27 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -22,25 +22,25 @@ - The Ant Financial - http://www.antfin.com/ + SOFAStack + https://www.sofastack.tech/ Geng Zhang - zhanggeng.zg@antfin.com - The Ant Financial + zhanggeng.zg@antgroup.com + SOFAStack Wei Li - lw111072@antfin.com - The Ant Financial + lw111072@antgroup.com + SOFAStack ZhiYuan Lei - zhiyuan.lzy@antfin.com - The Ant Financial + zhiyuan.lzy@antgroup.com + SOFAStack diff --git a/pom.xml b/pom.xml index 9725bf743..e3773ff71 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,13 @@ sofa-rpc-parent ${revision} pom - [SOFA] - RPC Framework - http://www.antfin.com + [SOFA] RPC Framework + https://www.sofastack.tech [SOFA] RPC Framework of Java. - The Ant Financial - http://www.antfin.com/ + SOFAStack + https://www.sofastack.tech/ From 512c6fc75695b71a2db07083c3a2cf3fd18f1bc4 Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 14 Oct 2024 10:33:12 +0800 Subject: [PATCH 54/64] enhance code (#1453) Co-authored-by: liujianjun.ljj --- .../sofa-rpc/serialize_blacklist.txt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt index ba6c18ce6..413a5045c 100644 --- a/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt +++ b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt @@ -11,7 +11,8 @@ com.alibaba.fastjson.annotation. com.alibaba.hotcode.internal.org.apache.commons.collections.functors. com.alipay.custrelation.service.model.redress. com.alipay.oceanbase.obproxy.druid.pool. -com.caucho. +com.caucho.hessian.test.TestCons +com.caucho.naming.Qname com.ibatis. com.ibm.jtc.jax.xml.bind.v2.runtime.unmarshaller. com.ibm.xltxe.rnm1.xtq.bcel.util. @@ -32,16 +33,6 @@ flex.messaging.util.concurrent. groovy.lang. java.awt. java.beans. -java.io.Closeable -java.io.Serializable -java.lang.AutoCloseable -java.lang.Cloneable -java.lang.Iterable -java.lang.ProcessBuilder -java.lang.Readable -java.lang.Runnable -java.lang.Thread -java.lang.UNIXProcess java.net.InetAddress java.net.Socket java.net.URL @@ -161,7 +152,16 @@ org.osjava.sj. org.python.core. org.quartz. org.slf4j. -org.springframework. +org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator$PartiallyComparableAdvisorHolder +org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor +org.springframework.beans.factory.BeanFactory +org.springframework.beans.factory.config.PropertyPathFactoryBean +org.springframework.beans.factory.support.DefaultListableBeanFactory +org.springframework.jndi.support.SimpleJndiBeanFactory +org.springframework.orm.jpa.AbstractEntityManagerFactoryBean +org.springframework.transaction.jta.JtaTransactionManager +org.springframework.jndi.JndiObjectTargetSource +org.springframework.beans.factory.config.MethodInvokingFactoryBean org.thymeleaf. org.yaml.snakeyaml.tokens. pstore.shaded.org.apache.commons.collections. From b7f02819ce64432c0154100e987a2526655e81ea Mon Sep 17 00:00:00 2001 From: bohrqiu Date: Mon, 14 Oct 2024 10:33:28 +0800 Subject: [PATCH 55/64] add SofaRejectedExecutionHandler for user-customized thread pool (#1450) * add SofaRejectedExecutionHandler for user custom thread pool * add RejectedExecutionHandler test case * format code * format code --- .../com/alipay/sofa/rpc/server/UserThreadPool.java | 1 + .../sofa/rpc/config/UserThreadPoolManagerTest.java | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java index 5eb20b539..2d74195b4 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/server/UserThreadPool.java @@ -113,6 +113,7 @@ protected Executor buildExecutor() { if (prestartAllCoreThreads) { threadPoolExecutor.prestartAllCoreThreads(); } + threadPoolExecutor.setRejectedExecutionHandler(new SofaRejectedExecutionHandler()); return threadPoolExecutor; } diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java index 810a61f2f..25fa22bd9 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/config/UserThreadPoolManagerTest.java @@ -18,10 +18,13 @@ import com.alipay.sofa.rpc.server.UserThreadPool; import com.alipay.sofa.rpc.server.UserVirtualThreadPool; +import com.alipay.sofa.rpc.server.SofaRejectedExecutionHandler; import org.junit.Assert; import org.junit.Test; + import java.util.Set; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; public class UserThreadPoolManagerTest { @@ -67,6 +70,16 @@ public void userThreadPoolBuildTest() { Assert.assertNull(result); } + @Test + public void testRejectedExecutionHandler() { + UserThreadPool userThreadPool = new UserThreadPool(); + Executor executorService = userThreadPool.getUserExecutor(); + Assert.assertTrue(executorService instanceof ThreadPoolExecutor); + RejectedExecutionHandler rejectedExecutionHandler = ((ThreadPoolExecutor) executorService) + .getRejectedExecutionHandler(); + Assert.assertTrue(rejectedExecutionHandler instanceof SofaRejectedExecutionHandler); + } + @Test public void userThreadPoolCompatibleTest() { UserThreadPool userThreadPool = new UserThreadPool(); From 1979f23f920b8831bded982a849f9d25b0adbf72 Mon Sep 17 00:00:00 2001 From: lo1nt Date: Mon, 14 Oct 2024 10:33:49 +0800 Subject: [PATCH 56/64] fix: update provider to null (#1452) Co-authored-by: Lo1nt --- .../sofa/rpc/client/AbstractCluster.java | 7 +- .../rpc/client/ClusterProviderUpdateTest.java | 194 ++++++++++++++++++ 2 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 core-impl/client/src/test/java/com/alipay/sofa/rpc/client/ClusterProviderUpdateTest.java diff --git a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java index 33fc4cc2a..2db6a6b1f 100644 --- a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java +++ b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java @@ -210,19 +210,22 @@ public void updateProviders(ProviderGroup providerGroup) { checkProviderInfo(providerGroup); ProviderGroup oldProviderGroup = addressHolder.getProviderGroup(providerGroup.getName()); if (ProviderHelper.isEmpty(providerGroup)) { + boolean previouslyEmpty = ProviderHelper.isEmpty(oldProviderGroup); addressHolder.updateProviders(providerGroup); - if (!ProviderHelper.isEmpty(oldProviderGroup)) { + if (!previouslyEmpty) { if (LOGGER.isWarnEnabled(consumerConfig.getAppName())) { LOGGER.warnWithApp(consumerConfig.getAppName(), "Provider list is emptied, may be all " + "providers has been closed, or this consumer has been add to blacklist"); - closeTransports(); } + closeTransports(); } } else { addressHolder.updateProviders(providerGroup); connectionHolder.updateProviders(providerGroup); } if (EventBus.isEnable(ProviderInfoUpdateEvent.class)) { + // see: https://github.com/sofastack/sofa-rpc/issues/1442 + // there is a swallow copy problem which makes the oldProviderGroup same as providerGroup ProviderInfoUpdateEvent event = new ProviderInfoUpdateEvent(consumerConfig, oldProviderGroup, providerGroup); EventBus.post(event); } diff --git a/core-impl/client/src/test/java/com/alipay/sofa/rpc/client/ClusterProviderUpdateTest.java b/core-impl/client/src/test/java/com/alipay/sofa/rpc/client/ClusterProviderUpdateTest.java new file mode 100644 index 000000000..240fb73e3 --- /dev/null +++ b/core-impl/client/src/test/java/com/alipay/sofa/rpc/client/ClusterProviderUpdateTest.java @@ -0,0 +1,194 @@ +/* + * 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 com.alipay.sofa.rpc.client; + +import com.alipay.sofa.rpc.bootstrap.ConsumerBootstrap; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.transport.ClientTransport; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author junyuan + * @version ClusterProviderUpdateTest.java, v 0.1 2024-10-11 11:04 junyuan Exp $ + */ +public class ClusterProviderUpdateTest { + private static final AbstractCluster cluster; + + static { + ConsumerBootstrap bootstrap = new ConsumerBootstrap(new ConsumerConfig()) { + @Override + public Object refer() { + return null; + } + + @Override + public void unRefer() { + + } + + @Override + public Object getProxyIns() { + return null; + } + + @Override + public Cluster getCluster() { + return null; + } + + @Override + public List subscribe() { + return null; + } + + @Override + public boolean isSubscribed() { + return false; + } + }; + + cluster = new AbstractCluster(bootstrap) { + @Override + protected SofaResponse doInvoke(SofaRequest msg) throws SofaRpcException { + return null; + } + }; + + cluster.addressHolder = new SingleGroupAddressHolder(null); + cluster.connectionHolder = new TestUseConnectionHolder(null); + } + + @Test + public void testUpdateProvider() { + String groupName = "testUpdateProvider-Group"; + List providerList = Arrays.asList( + ProviderHelper.toProviderInfo("127.0.0.1:12200"), + ProviderHelper.toProviderInfo("127.0.0.1:12201"), + ProviderHelper.toProviderInfo("127.0.0.1:12202")); + ProviderGroup g = new ProviderGroup(groupName, providerList); + cluster.updateProviders(g); + + Assert.assertEquals(cluster.currentProviderList().size(), providerList.size()); + + cluster.updateProviders(new ProviderGroup(groupName, null)); + + Assert.assertTrue(cluster.getAddressHolder().getProviderGroup(groupName).isEmpty()); + Assert.assertEquals( 1, ((TestUseConnectionHolder)cluster.connectionHolder).calledCloseAllClientTransports.get()); + } + + + private static class TestUseConnectionHolder extends ConnectionHolder { + Set connections = new HashSet<>(); + + AtomicInteger calledCloseAllClientTransports = new AtomicInteger(); + + /** + * 构造函数 + * + * @param consumerBootstrap 服务消费者配置 + */ + protected TestUseConnectionHolder(ConsumerBootstrap consumerBootstrap) { + super(consumerBootstrap); + } + + @Override + public void closeAllClientTransports(DestroyHook destroyHook) { + calledCloseAllClientTransports.getAndIncrement(); + } + + @Override + public ConcurrentMap getAvailableConnections() { + return null; + } + + @Override + public List getAvailableProviders() { + return null; + } + + @Override + public ClientTransport getAvailableClientTransport(ProviderInfo providerInfo) { + return null; + } + + @Override + public boolean isAvailableEmpty() { + return false; + } + + @Override + public Collection currentProviderList() { + return null; + } + + @Override + public void setUnavailable(ProviderInfo providerInfo, ClientTransport transport) { + + } + + @Override + public void addProvider(ProviderGroup providerGroup) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public void removeProvider(ProviderGroup providerGroup) { + throw new UnsupportedOperationException("not implemented"); + + } + + @Override + public void updateProviders(ProviderGroup providerGroup) { + for (ProviderInfo i : providerGroup.getProviderInfos()) { + connections.add(i); + } + } + + @Override + public void updateAllProviders(List providerGroups) { + + } + + @Override + public void destroy() { + + } + + @Override + public void destroy(DestroyHook hook) { + + } + + @Override + public void init() { + + } + } +} \ No newline at end of file From 60433bca9c1497cb480633b51e58ad59af0b38cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 11:20:53 +0800 Subject: [PATCH 57/64] chore(deps): bump commons-io:commons-io from 2.7 to 2.14.0 in /bom (#1451) Bumps commons-io:commons-io from 2.7 to 2.14.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/pom.xml b/bom/pom.xml index 7f7c3f10f..1eacea177 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -464,7 +464,7 @@ commons-io commons-io - 2.7 + 2.14.0 com.alipay.sofa From ffc3b93b64eeaf793fc54f5af453cc0bd866b529 Mon Sep 17 00:00:00 2001 From: evenliu Date: Mon, 14 Oct 2024 17:14:20 +0800 Subject: [PATCH 58/64] Mesh Registry support custom group for sofa registry. (#1454) Co-authored-by: liujianjun.ljj --- .../sofa/rpc/registry/mesh/MeshRegistry.java | 18 ++++++++++ .../mesh/model/PublishServiceRequest.java | 11 ++++++ .../mesh/model/SubscribeServiceRequest.java | 35 +++++++++++++++---- .../mesh/model/UnPublishServiceRequest.java | 10 ++++++ .../mesh/model/UnSubscribeServiceRequest.java | 11 ++++++ .../rpc/registry/mesh/MeshRegistryTest.java | 16 +++++++-- 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistry.java b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistry.java index 278fadd25..a9fdafbf0 100644 --- a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistry.java +++ b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistry.java @@ -20,6 +20,7 @@ import com.alipay.sofa.rpc.client.ProviderInfo; import com.alipay.sofa.rpc.common.struct.NamedThreadFactory; import com.alipay.sofa.rpc.common.utils.CommonUtils; +import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.config.ConsumerConfig; import com.alipay.sofa.rpc.config.ProviderConfig; import com.alipay.sofa.rpc.config.RegistryConfig; @@ -184,6 +185,10 @@ protected PublishServiceRequest buildPublishServiceRequest(String serviceName, S providerMetaInfo.setVersion(VERSION); providerMetaInfo.setProperties(providerInfo.getStaticAttrs()); publishServiceRequest.setProviderMetaInfo(providerMetaInfo); + String group = providerInfo.getStaticAttrs().get(SofaRegistryConstants.SOFA_GROUP_KEY); + if (StringUtils.isNotBlank(group)) { + publishServiceRequest.setGroup(group); + } return publishServiceRequest; } @@ -233,6 +238,10 @@ protected UnPublishServiceRequest buildUnPublishServiceRequest(String serviceNam UnPublishServiceRequest unPublishServiceRequest = new UnPublishServiceRequest(); unPublishServiceRequest.setServiceName(serviceName); unPublishServiceRequest.setProtocolType(providerInfo.getProtocolType()); + String group = providerInfo.getStaticAttr(SofaRegistryConstants.SOFA_GROUP_KEY); + if (StringUtils.isNotBlank(group)) { + unPublishServiceRequest.setGroup(group); + } return unPublishServiceRequest; } @@ -303,6 +312,11 @@ protected SubscribeServiceRequest buildSubscribeServiceRequest(ConsumerConfig co SubscribeServiceRequest subscribeRequest = new SubscribeServiceRequest(); subscribeRequest.setServiceName(key); subscribeRequest.setProtocolType(consumerConfig.getProtocol()); + subscribeRequest.setProperties(consumerConfig.getParameters()); + String group = consumerConfig.getParameter(SofaRegistryConstants.SOFA_GROUP_KEY); + if (StringUtils.isNotBlank(group)) { + subscribeRequest.setGroup(group); + } return subscribeRequest; } @@ -368,6 +382,10 @@ protected UnSubscribeServiceRequest buildUnSubscribeServiceRequest(ConsumerConfi String key = MeshRegistryHelper.buildMeshKey(config, config.getProtocol()); unsubscribeRequest.setServiceName(key); unsubscribeRequest.setProtocolType(config.getProtocol()); + String group = config.getParameter(SofaRegistryConstants.SOFA_GROUP_KEY); + if (StringUtils.isNotBlank(group)) { + unsubscribeRequest.setGroup(group); + } return unsubscribeRequest; } diff --git a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/PublishServiceRequest.java b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/PublishServiceRequest.java index 8911eb9fa..895aa8241 100644 --- a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/PublishServiceRequest.java +++ b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/PublishServiceRequest.java @@ -32,6 +32,8 @@ public class PublishServiceRequest { private boolean onlyPublishInCloud; + private String group; + public String getServiceName() { return serviceName; } @@ -64,6 +66,14 @@ public void setOnlyPublishInCloud(boolean onlyPublishInCloud) { this.onlyPublishInCloud = onlyPublishInCloud; } + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("PublishServiceRequest{"); @@ -71,6 +81,7 @@ public String toString() { sb.append(", protocolType='").append(protocolType).append('\''); sb.append(", providerMetaInfo=").append(providerMetaInfo); sb.append(", onlyPublishInCloud=").append(onlyPublishInCloud); + sb.append(", group='").append(group).append('\''); sb.append('}'); return sb.toString(); } diff --git a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/SubscribeServiceRequest.java b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/SubscribeServiceRequest.java index 27fbc5f22..118a71846 100644 --- a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/SubscribeServiceRequest.java +++ b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/SubscribeServiceRequest.java @@ -16,25 +16,31 @@ */ package com.alipay.sofa.rpc.registry.mesh.model; +import java.util.Map; + /** * @author bystander * @version $Id: PublishServiceRequest.java, v 0.1 2018年04月03日 11:27 AM bystander Exp $ */ public class SubscribeServiceRequest { - private String serviceName; + private String serviceName; //这个值是类似DEFAULT/XFIRE这种,也有可能是tr - private String protocolType; + private String protocolType; //this should be xxx-pool.alipay.com or xxx.alipay.com,can be null - private String targetAppAddress; + private String targetAppAddress; + + private boolean vipEnforce; + + private boolean vipOnly; - private boolean vipEnforce; + private boolean localCloudFirst; - private boolean vipOnly; + private String group; - private boolean localCloudFirst; + private Map properties; public String getServiceName() { return serviceName; @@ -84,6 +90,22 @@ public void setLocalCloudFirst(boolean localCloudFirst) { this.localCloudFirst = localCloudFirst; } + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("SubscribeServiceRequest{"); @@ -93,6 +115,7 @@ public String toString() { sb.append(", vipEnforce=").append(vipEnforce); sb.append(", vipOnly=").append(vipOnly); sb.append(", localCloudFirst=").append(localCloudFirst); + sb.append(", group='").append(group).append('\''); sb.append('}'); return sb.toString(); } diff --git a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnPublishServiceRequest.java b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnPublishServiceRequest.java index 7cfd3ad32..577fe2e50 100644 --- a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnPublishServiceRequest.java +++ b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnPublishServiceRequest.java @@ -27,6 +27,8 @@ public class UnPublishServiceRequest { //这个值是类似DEFAULT/XFIRE这种,也有可能是tr private String protocolType; + private String group; + public String getServiceName() { return serviceName; } @@ -43,6 +45,14 @@ public void setProtocolType(String protocolType) { this.protocolType = protocolType; } + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("UnPublishServiceRequest{"); diff --git a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnSubscribeServiceRequest.java b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnSubscribeServiceRequest.java index 1cf0e8f2c..86150c591 100644 --- a/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnSubscribeServiceRequest.java +++ b/registry/registry-mesh/src/main/java/com/alipay/sofa/rpc/registry/mesh/model/UnSubscribeServiceRequest.java @@ -30,6 +30,8 @@ public class UnSubscribeServiceRequest { //这个值是类似DEFAULT/XFIRE这种,也有可能是tr private String protocolType; + private String group; + public String getServiceName() { return serviceName; } @@ -54,12 +56,21 @@ public void setProtocolType(String protocolType) { this.protocolType = protocolType; } + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer("UnSubscribeServiceRequest{"); sb.append("serviceName='").append(serviceName).append('\''); sb.append(", targetAppAddress='").append(targetAppAddress).append('\''); sb.append(", protocolType='").append(protocolType).append('\''); + sb.append(", group='").append(group).append('\''); sb.append('}'); return sb.toString(); } diff --git a/registry/registry-mesh/src/test/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistryTest.java b/registry/registry-mesh/src/test/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistryTest.java index ca478aa54..c896c55b0 100644 --- a/registry/registry-mesh/src/test/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistryTest.java +++ b/registry/registry-mesh/src/test/java/com/alipay/sofa/rpc/registry/mesh/MeshRegistryTest.java @@ -167,6 +167,8 @@ public void testOnlyPublish() throws InterruptedException { public void testAll() throws Exception { int timeoutPerSub = 1000; + Map parameter = new HashMap<>(); + parameter.put(SofaRegistryConstants.SOFA_GROUP_KEY, "SOFA_TEST"); ServerConfig serverConfig = new ServerConfig() .setProtocol("bolt") @@ -183,7 +185,8 @@ public void testAll() throws Exception { .setSerialization("hessian2") .setServer(serverConfig) .setWeight(222) - .setTimeout(3000); + .setTimeout(3000) + .setParameters(parameter); // 注册 registry.register(provider); @@ -196,7 +199,8 @@ public void testAll() throws Exception { .setSubscribe(true) .setSerialization("java") .setInvokeType("sync") - .setTimeout(4444); + .setTimeout(4444) + .setParameters(parameter); String tag0 = MeshRegistryHelper.buildMeshKey(provider, serverConfig.getProtocol()); String tag1 = MeshRegistryHelper.buildMeshKey(consumer, consumer.getProtocol()); @@ -205,6 +209,7 @@ public void testAll() throws Exception { PublishServiceRequest publishServiceRequest = registry.buildPublishServiceRequest(tag0, serverConfig.getProtocol(), providerInfo, "test-server"); Assert.assertEquals(serverConfig.getProtocol(), publishServiceRequest.getProtocolType()); + Assert.assertEquals("SOFA_TEST", publishServiceRequest.getGroup()); // 订阅 MeshRegistryTest.MockProviderInfoListener providerInfoListener = new MeshRegistryTest.MockProviderInfoListener(); @@ -216,6 +221,8 @@ public void testAll() throws Exception { Assert.assertTrue(ps.toString(), ps.size() == 1); SubscribeServiceRequest subscribeServiceRequest = registry.buildSubscribeServiceRequest(consumer); Assert.assertEquals(consumer.getProtocol(), subscribeServiceRequest.getProtocolType()); + Assert.assertEquals("SOFA_TEST", subscribeServiceRequest.getGroup()); + Assert.assertNotNull(subscribeServiceRequest.getProperties()); // 反注册 CountDownLatch latch = new CountDownLatch(1); @@ -226,6 +233,7 @@ public void testAll() throws Exception { Assert.assertTrue(ps.size() == 1); UnPublishServiceRequest unPublishServiceRequest = registry.buildUnPublishServiceRequest(tag0, providerInfo); Assert.assertEquals(serverConfig.getProtocol(), unPublishServiceRequest.getProtocolType()); + Assert.assertEquals("SOFA_TEST", unPublishServiceRequest.getGroup()); // 一次发2个端口的再次注册 latch = new CountDownLatch(1); @@ -246,7 +254,8 @@ public void testAll() throws Exception { .setSubscribe(true) .setSerialization("java") .setInvokeType("sync") - .setTimeout(4444); + .setTimeout(4444) + .setParameters(parameter); CountDownLatch latch2 = new CountDownLatch(1); MeshRegistryTest.MockProviderInfoListener providerInfoListener2 = new MeshRegistryTest.MockProviderInfoListener(); providerInfoListener2.setCountDownLatch(latch2); @@ -261,6 +270,7 @@ public void testAll() throws Exception { registry.unSubscribe(consumer); UnSubscribeServiceRequest unSubscribeServiceRequest = registry.buildUnSubscribeServiceRequest(consumer); Assert.assertEquals(consumer.getProtocol(), unSubscribeServiceRequest.getProtocolType()); + Assert.assertEquals("SOFA_TEST", unSubscribeServiceRequest.getGroup()); // 批量反注册,判断订阅者2的数据 latch = new CountDownLatch(1); From 8b8fc7d761b6e61e5877c55a1288123d13581afd Mon Sep 17 00:00:00 2001 From: evenliu Date: Thu, 17 Oct 2024 17:04:12 +0800 Subject: [PATCH 59/64] release rpc version 5.13.2 (#1455) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 62800ab27..0034d3f69 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.2-SNAPSHOT + 5.13.2 ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 1eacea177..7a79b1b1b 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.2-SNAPSHOT + 5.13.2 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index 979c0e1cf..ca8533b36 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -37,6 +37,6 @@ public final class Version { /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.2_20240922142359"; + public static final String BUILD_VERSION = "5.13.2_20241016193119"; } diff --git a/pom.xml b/pom.xml index e3773ff71..d9329de5f 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.2-SNAPSHOT + 5.13.2 1.33 true true From 3e317ff7449a5822047ccfed5d8a600b6dad2405 Mon Sep 17 00:00:00 2001 From: Narziss Date: Thu, 31 Oct 2024 20:41:55 +0800 Subject: [PATCH 60/64] Optimize dynamic config: integrate Zookeeper & Nacos, support interface-level dynamic config (#1430) * integrate Zookeeper and Nacos as configuration centers * support dynamic config at the interface level * Optimize interface-level dynamic config * Modify dynamic config test * Add DynamicUrl * Optimize config update process * Modify config update process * Modify ApolloDynamicConfigManagerTest --- all/pom.xml | 12 + .../bootstrap/DefaultConsumerBootstrap.java | 69 +++++- .../apollo/ApolloDynamicConfigManager.java | 116 ++++++++- .../ApolloDynamicConfigManagerTest.java | 19 +- config/config-nacos/pom.xml | 107 ++++++++ .../nacos/NacosDynamicConfigManager.java | 207 ++++++++++++++++ ...ipay.sofa.rpc.dynamic.DynamicConfigManager | 2 + .../nacos/NacosDynamicConfigManagerTest.java | 58 +++++ .../config-nacos/src/test/resources/log4j.xml | 16 ++ config/config-zk/pom.xml | 117 +++++++++ .../zk/ZookeeperDynamicConfigManager.java | 231 ++++++++++++++++++ ...ipay.sofa.rpc.dynamic.DynamicConfigManager | 1 + .../zk/ZookeeperDynamicConfigManagerTest.java | 58 +++++ config/config-zk/src/test/resources/log4j.xml | 16 ++ config/pom.xml | 2 + .../sofa/rpc/client/AbstractCluster.java | 3 +- .../sofa/rpc/client/lb/AutoLoadBalancer.java | 2 +- .../rpc/config/AbstractInterfaceConfig.java | 40 ++- .../sofa/rpc/dynamic/ConfigChangeType.java | 39 +++ .../sofa/rpc/dynamic/ConfigChangedEvent.java | 88 +++++++ .../sofa/rpc/dynamic/DynamicConfigKeys.java | 25 +- .../rpc/dynamic/DynamicConfigManager.java | 54 +++- .../dynamic/DynamicConfigManagerFactory.java | 2 +- .../alipay/sofa/rpc/dynamic/DynamicUrl.java | 102 ++++++++ .../sofa/rpc/listener/ConfigListener.java | 11 + .../sofa/rpc/dynamic/DynamicUrlTest.java | 79 ++++++ test/test-integration/pom.xml | 20 +- .../test/config/ApolloDynamicConfigTest.java | 97 ++++++++ .../test/config/NacosDynamicConfigTest.java | 81 ++++++ .../config/ZookeeperDynamicConfigTest.java | 97 ++++++++ .../sofa/rpc/test/config/base/BaseZkTest.java | 62 +++++ 31 files changed, 1793 insertions(+), 40 deletions(-) create mode 100644 config/config-nacos/pom.xml create mode 100644 config/config-nacos/src/main/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManager.java create mode 100644 config/config-nacos/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager create mode 100644 config/config-nacos/src/test/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManagerTest.java create mode 100644 config/config-nacos/src/test/resources/log4j.xml create mode 100644 config/config-zk/pom.xml create mode 100644 config/config-zk/src/main/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManager.java create mode 100644 config/config-zk/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager create mode 100644 config/config-zk/src/test/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManagerTest.java create mode 100644 config/config-zk/src/test/resources/log4j.xml create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangeType.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangedEvent.java create mode 100644 core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicUrl.java create mode 100644 core/api/src/test/java/com/alipay/sofa/rpc/dynamic/DynamicUrlTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ApolloDynamicConfigTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/NacosDynamicConfigTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ZookeeperDynamicConfigTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/base/BaseZkTest.java diff --git a/all/pom.xml b/all/pom.xml index 0034d3f69..3351476d9 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -304,6 +304,16 @@ sofa-rpc-config-apollo ${project.version} + + com.alipay.sofa + sofa-rpc-config-zk + ${project.version} + + + com.alipay.sofa + sofa-rpc-config-nacos + ${project.version} + com.alipay.sofa bolt @@ -553,6 +563,8 @@ com.alipay.sofa:sofa-rpc-tracer-opentracing-resteasy com.alipay.sofa:sofa-rpc-tracer-opentracing-triple com.alipay.sofa:sofa-rpc-config-apollo + com.alipay.sofa:sofa-rpc-config-zk + com.alipay.sofa:sofa-rpc-config-nacos com.alipay.sofa:sofa-rpc-doc-swagger diff --git a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultConsumerBootstrap.java b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultConsumerBootstrap.java index f6ba175a7..7e559d89b 100644 --- a/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultConsumerBootstrap.java +++ b/bootstrap/bootstrap-api/src/main/java/com/alipay/sofa/rpc/bootstrap/DefaultConsumerBootstrap.java @@ -20,6 +20,7 @@ import com.alipay.sofa.rpc.client.Cluster; import com.alipay.sofa.rpc.client.ClusterFactory; import com.alipay.sofa.rpc.client.ProviderGroup; +import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.common.SofaConfigs; import com.alipay.sofa.rpc.common.SofaOptions; import com.alipay.sofa.rpc.common.utils.CommonUtils; @@ -28,9 +29,12 @@ import com.alipay.sofa.rpc.config.RegistryConfig; import com.alipay.sofa.rpc.context.RpcRuntimeContext; import com.alipay.sofa.rpc.core.exception.SofaRpcRuntimeException; +import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent; +import com.alipay.sofa.rpc.dynamic.ConfigChangeType; import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.DynamicUrl; import com.alipay.sofa.rpc.ext.Extension; import com.alipay.sofa.rpc.invoke.Invoker; import com.alipay.sofa.rpc.listener.ConfigListener; @@ -44,8 +48,10 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; @@ -54,6 +60,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.alipay.sofa.rpc.common.RpcConstants.REGISTRY_PROTOCOL_DOMAIN; +import static com.alipay.sofa.common.config.SofaConfigs.getOrDefault; /** * Default consumer bootstrap. @@ -146,7 +153,8 @@ public T refer() { // build cluster cluster = ClusterFactory.getCluster(this); // build listeners - consumerConfig.setConfigListener(buildConfigListener(this)); + ConfigListener configListener = buildConfigListener(this); + consumerConfig.setConfigListener(configListener); consumerConfig.setProviderInfoListener(buildProviderInfoListener(this)); // init cluster cluster.init(); @@ -156,13 +164,25 @@ public T refer() { proxyIns = (T) ProxyFactory.buildProxy(consumerConfig.getProxy(), consumerConfig.getProxyClass(), proxyInvoker); - //动态配置 + //请求级别动态配置参数 final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS); if (StringUtils.isNotBlank(dynamicAlias)) { final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager( - consumerConfig.getAppName(), dynamicAlias); + consumerConfig.getAppName(), dynamicAlias); dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId()); } + + //接口级别动态配置参数 + Boolean dynamicConfigRefreshEnable = getOrDefault(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE); + String configCenterAddress = getOrDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS); + if (dynamicConfigRefreshEnable && StringUtils.isNotBlank(configCenterAddress)) { + DynamicUrl dynamicUrl = new DynamicUrl(configCenterAddress); + //启用接口级别动态配置 + final DynamicConfigManager dynamicManager = DynamicConfigManagerFactory.getDynamicManager( + consumerConfig.getAppName(), dynamicUrl.getProtocol()); + dynamicManager.addListener(consumerConfig.getInterfaceId(), configListener); + dynamicManager.initServiceConfiguration(consumerConfig.getInterfaceId(), configListener); + } } catch (Exception e) { if (cluster != null) { cluster.destroy(); @@ -438,8 +458,47 @@ public void updateAllProviders(List groups) { */ private class ConsumerAttributeListener implements ConfigListener { + // 可以动态配置的选项 + private final Set supportDynamicConfigKeys = new HashSet<>(); + private final Map newValueMap = new HashMap<>(); + + ConsumerAttributeListener() { + supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_TIMEOUT); + supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_RETRIES); + supportDynamicConfigKeys.add(RpcConstants.CONFIG_KEY_LOADBALANCER); + } + + @Override + public void process(ConfigChangedEvent event) { + // 清除上次的动态配置值缓存 + consumerConfig.getDynamicConfigValueCache().clear(); + // 获取对应配置项的默认值 + for (String key : newValueMap.keySet()) { + if (consumerConfig.getConfigValueCache().get(key) != null) { + newValueMap.put(key, String.valueOf(consumerConfig.getConfigValueCache().get(key))); + } else { + newValueMap.put(key, null); + } + } + if (!event.getChangeType().equals(ConfigChangeType.DELETED)) { + // ADDED or MODIFIED + Map dynamicValueMap = event.getDynamicValueMap(); + for (String key : dynamicValueMap.keySet()) { + String tempKey = key.lastIndexOf(".") == -1 ? key : key.substring(key.lastIndexOf(".") + 1); + if (supportDynamicConfigKeys.contains(tempKey)) { + String value = dynamicValueMap.get(key); + if (StringUtils.isNotBlank(value)) { + consumerConfig.getDynamicConfigValueCache().put(key, value); + newValueMap.put(key, value); + } + } + } + } + attrUpdated(newValueMap); + } + @Override - public void configChanged(Map newValue) { + public void configChanged(Map newValueMap) { } @@ -452,7 +511,7 @@ public synchronized void attrUpdated(Map newValueMap) { Map oldValues = new HashMap(); boolean rerefer = false; try { // 检查是否有变化 - // 是否过滤map? + // 是否过滤map? for (Map.Entry entry : newValues.entrySet()) { String newValue = entry.getValue(); String oldValue = consumerConfig.queryAttribute(entry.getKey()); diff --git a/config/config-apollo/src/main/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManager.java b/config/config-apollo/src/main/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManager.java index 35367d5ca..d7aec05c5 100644 --- a/config/config-apollo/src/main/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManager.java +++ b/config/config-apollo/src/main/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManager.java @@ -16,13 +16,30 @@ */ package com.alipay.sofa.rpc.dynamic.apollo; +import com.alipay.sofa.common.config.SofaConfigs; import com.alipay.sofa.rpc.auth.AuthRuleGroup; +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.dynamic.ConfigChangeType; +import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent; import com.alipay.sofa.rpc.dynamic.DynamicConfigKeyHelper; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; import com.alipay.sofa.rpc.dynamic.DynamicHelper; import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.listener.ConfigListener; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.ConfigService; +import com.ctrip.framework.apollo.enums.PropertyChangeType; +import com.ctrip.framework.apollo.model.ConfigChange; + +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArraySet; /** * @author bystander @@ -34,41 +51,88 @@ @Extension(value = "apollo", override = true) public class ApolloDynamicConfigManager extends DynamicConfigManager { - private Config config; + private final static Logger LOGGER = LoggerFactory.getLogger(ApolloDynamicConfigManager.class); + + private static final String APOLLO_APPID_KEY = "app.id"; + + private static final String APOLLO_ADDR_KEY = "apollo.meta"; + + private static final String APOLLO_CLUSTER_KEY = "apollo.cluster"; + + private static final String APOLLO_PARAM_APPID_KEY = "appId"; + + private static final String APOLLO_PARAM_CLUSTER_KEY = "cluster"; + + private static final String APOLLO_PARAM_NAMESPACE_KEY = "namespace"; + + private static final String APOLLO_PROTOCOL_PREFIX = "http://"; + + private final ConcurrentMap watchListenerMap = new ConcurrentHashMap<>(); + + private final Config config; protected ApolloDynamicConfigManager(String appName) { - super(appName); - config = ConfigService.getAppConfig(); + super(appName, SofaConfigs.getOrCustomDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS, "")); + if (getDynamicUrl() != null) { + if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_APPID_KEY))) { + System.setProperty(APOLLO_APPID_KEY, getDynamicUrl().getParam(APOLLO_PARAM_APPID_KEY)); + } + if (StringUtils.isNotBlank(getDynamicUrl().getAddress())) { + System.setProperty(APOLLO_ADDR_KEY, APOLLO_PROTOCOL_PREFIX + getDynamicUrl().getAddress()); + } + if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_CLUSTER_KEY))) { + System.setProperty(APOLLO_CLUSTER_KEY, getDynamicUrl().getParam(APOLLO_PARAM_CLUSTER_KEY)); + } + if (StringUtils.isNotBlank(getDynamicUrl().getParam(APOLLO_PARAM_NAMESPACE_KEY))) { + config = ConfigService.getConfig(getDynamicUrl().getParam(APOLLO_PARAM_NAMESPACE_KEY)); + } else { + config = ConfigService.getAppConfig(); + } + } else { + config = ConfigService.getAppConfig(); + } } @Override public void initServiceConfiguration(String service) { - //TODO not now + // TODO 暂不支持 + } + + @Override + public void initServiceConfiguration(String service, ConfigListener listener) { + try { + String rawConfig = config.getProperty(service, ""); + if (StringUtils.isNotBlank(rawConfig)) { + listener.process(new ConfigChangedEvent(service, rawConfig)); + } + } catch (Exception e) { + LOGGER.error("Init service configuration error", e); + } } @Override public String getProviderServiceProperty(String service, String key) { return config.getProperty(DynamicConfigKeyHelper.buildProviderServiceProKey(service, key), - DynamicHelper.DEFAULT_DYNAMIC_VALUE); + DynamicHelper.DEFAULT_DYNAMIC_VALUE); } @Override public String getConsumerServiceProperty(String service, String key) { return config.getProperty(DynamicConfigKeyHelper.buildConsumerServiceProKey(service, key), - DynamicHelper.DEFAULT_DYNAMIC_VALUE); + DynamicHelper.DEFAULT_DYNAMIC_VALUE); } @Override public String getProviderMethodProperty(String service, String method, String key) { return config.getProperty(DynamicConfigKeyHelper.buildProviderMethodProKey(service, method, key), - DynamicHelper.DEFAULT_DYNAMIC_VALUE); + DynamicHelper.DEFAULT_DYNAMIC_VALUE); } @Override public String getConsumerMethodProperty(String service, String method, String key) { return config.getProperty(DynamicConfigKeyHelper.buildConsumerMethodProKey(service, method, key), - DynamicHelper.DEFAULT_DYNAMIC_VALUE); + DynamicHelper.DEFAULT_DYNAMIC_VALUE); } @@ -77,4 +141,40 @@ public AuthRuleGroup getServiceAuthRule(String service) { //TODO 暂不支持 return null; } + + @Override + public void addListener(String key, ConfigListener listener) { + ApolloListener apolloListener = watchListenerMap.computeIfAbsent(key, k -> new ApolloListener()); + apolloListener.addListener(listener); + config.addChangeListener(apolloListener, Collections.singleton(key)); + } + + public static class ApolloListener implements ConfigChangeListener { + + private final Set listeners = new CopyOnWriteArraySet<>(); + + @Override + public void onChange(com.ctrip.framework.apollo.model.ConfigChangeEvent changeEvent) { + for (String key : changeEvent.changedKeys()) { + ConfigChange change = changeEvent.getChange(key); + ConfigChangedEvent event = + new ConfigChangedEvent(key, change.getNewValue(), getChangeType(change)); + listeners.forEach(listener -> listener.process(event)); + } + } + + private ConfigChangeType getChangeType(ConfigChange change) { + if (change.getChangeType() == PropertyChangeType.DELETED) { + return ConfigChangeType.DELETED; + } + if (change.getChangeType() == PropertyChangeType.ADDED) { + return ConfigChangeType.ADDED; + } + return ConfigChangeType.MODIFIED; + } + + void addListener(ConfigListener configListener) { + this.listeners.add(configListener); + } + } } \ No newline at end of file diff --git a/config/config-apollo/src/test/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManagerTest.java b/config/config-apollo/src/test/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManagerTest.java index 5fbb4daf0..2b08e90d3 100644 --- a/config/config-apollo/src/test/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManagerTest.java +++ b/config/config-apollo/src/test/java/com/alipay/sofa/rpc/dynamic/apollo/ApolloDynamicConfigManagerTest.java @@ -16,6 +16,8 @@ */ package com.alipay.sofa.rpc.dynamic.apollo; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; import com.alipay.sofa.rpc.dynamic.DynamicHelper; import com.alipay.sofa.rpc.log.Logger; import com.alipay.sofa.rpc.log.LoggerFactory; @@ -24,10 +26,11 @@ public class ApolloDynamicConfigManagerTest { - private final static Logger logger = LoggerFactory - .getLogger(ApolloDynamicConfigManagerTest.class); + private final static Logger logger = LoggerFactory + .getLogger(ApolloDynamicConfigManagerTest.class); - private ApolloDynamicConfigManager apolloDynamicConfigManager = new ApolloDynamicConfigManager("test"); + private DynamicConfigManager apolloDynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager("test", + "apollo"); @Test public void getProviderServiceProperty() { @@ -37,17 +40,19 @@ public void getProviderServiceProperty() { @Test public void getConsumerServiceProperty() { + String result = apolloDynamicConfigManager.getConsumerServiceProperty("serviceName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); } @Test public void getProviderMethodProperty() { + String result = apolloDynamicConfigManager.getProviderMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); } @Test public void getConsumerMethodProperty() { - } - - @Test - public void getServiceAuthRule() { + String result = apolloDynamicConfigManager.getConsumerMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); } } \ No newline at end of file diff --git a/config/config-nacos/pom.xml b/config/config-nacos/pom.xml new file mode 100644 index 000000000..4e0d8740b --- /dev/null +++ b/config/config-nacos/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + + com.alipay.sofa + sofa-rpc-config + ${revision} + + + sofa-rpc-config-nacos + + + + com.alipay.sofa + sofa-rpc-log-common-tools + + + com.alipay.sofa + sofa-rpc-log + + + com.alipay.sofa + sofa-rpc-api + + + + com.alibaba.nacos + nacos-client + + + org.slf4j + slf4j-log4j12 + test + + + junit + junit + test + + + + + + src/main/java + + + src/main/resources + false + + **/** + + + + src/test/java + + + src/test/resources + false + + **/** + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.source} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-install-plugin + + ${module.install.skip} + + + + org.apache.maven.plugins + maven-deploy-plugin + + ${module.deploy.skip} + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipTests} + + + **/*Test.java + + + once + + + + + diff --git a/config/config-nacos/src/main/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManager.java b/config/config-nacos/src/main/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManager.java new file mode 100644 index 000000000..366681927 --- /dev/null +++ b/config/config-nacos/src/main/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManager.java @@ -0,0 +1,207 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic.nacos; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.config.listener.AbstractSharedListener; +import com.alipay.sofa.common.config.SofaConfigs; +import com.alipay.sofa.rpc.auth.AuthRuleGroup; +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.dynamic.ConfigChangeType; +import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeyHelper; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicHelper; +import com.alipay.sofa.rpc.ext.Extension; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.ConfigFactory; +import com.alipay.sofa.rpc.listener.ConfigListener; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArraySet; +/** + * @author Narziss + * @version NaocsDynamicConfigManager.java, v 0.1 2024年07月26日 09:37 Narziss + */ + +@Extension(value = "nacos", override = true) +public class NacosDynamicConfigManager extends DynamicConfigManager { + + private final static Logger LOGGER = LoggerFactory.getLogger(NacosDynamicConfigManager.class); + + private static final long DEFAULT_TIMEOUT = 5000; + + private final String group; + + private final ConcurrentMap watchListenerMap = new ConcurrentHashMap<>(); + + private ConfigService configService; + + protected NacosDynamicConfigManager(String appName) { + super(appName, SofaConfigs.getOrCustomDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS, "nacos://127.0.0.1:8848")); + group = appName; + Properties nacosConfig = new Properties(); + nacosConfig.put(PropertyKeyConst.SERVER_ADDR, getDynamicUrl().getAddress()); + nacosConfig.putAll(getDynamicUrl().getParams()); + try { + configService = ConfigFactory.createConfigService(nacosConfig); + } catch (Exception e) { + LOGGER.error("Failed to create ConfigService", e); + } + } + + @Override + public void initServiceConfiguration(String service) { + // TODO 暂不支持 + } + + @Override + public void initServiceConfiguration(String service, ConfigListener listener) { + try { + String rawConfig = configService.getConfig(service, group, DEFAULT_TIMEOUT); + if (!StringUtils.isEmpty(rawConfig)) { + listener.process(new ConfigChangedEvent(service, rawConfig)); + } + } catch (Exception e) { + LOGGER.error("Failed to getConfig for key:{}, group:{}", service, group, e); + } + } + + @Override + public String getProviderServiceProperty(String service, String key) { + try { + String configValue = configService.getConfig( + DynamicConfigKeyHelper.buildProviderServiceProKey(service, key), + group, DEFAULT_TIMEOUT); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getConsumerServiceProperty(String service, String key) { + try { + String configValue = configService.getConfig( + DynamicConfigKeyHelper.buildConsumerServiceProKey(service, key), + group, DEFAULT_TIMEOUT); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getProviderMethodProperty(String service, String method, String key) { + try { + String configValue = configService.getConfig( + DynamicConfigKeyHelper.buildProviderMethodProKey(service, method, key), + group, DEFAULT_TIMEOUT); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getConsumerMethodProperty(String service, String method, String key) { + try { + String configValue = configService.getConfig( + DynamicConfigKeyHelper.buildConsumerMethodProKey(service, method, key), + group, DEFAULT_TIMEOUT); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public AuthRuleGroup getServiceAuthRule(String service) { + //TODO 暂不支持 + return null; + } + + @Override + public void addListener(String key, ConfigListener listener) { + NacosConfigListener nacosConfigListener = watchListenerMap.computeIfAbsent( + key, k -> createTargetListener(key)); + nacosConfigListener.addListener(listener); + try { + configService.addListener(key, group, nacosConfigListener); + } catch (Exception e) { + LOGGER.error("Failed to add listener for key:{}, group:{}", key, group, e); + } + } + + private NacosConfigListener createTargetListener(String key) { + NacosConfigListener configListener = new NacosConfigListener(); + configListener.fillContext(key, group); + return configListener; + } + + public static class NacosConfigListener extends AbstractSharedListener { + + private final Set listeners = new CopyOnWriteArraySet<>(); + + /** + * cache data to store old value + */ + private final Map cacheData = new ConcurrentHashMap<>(); + + /** + * receive config change event + * + * @param dataId data ID + * @param group group + * @param configInfo content + */ + @Override + public void innerReceive(String dataId, String group, String configInfo) { + String oldValue = cacheData.get(dataId); + ConfigChangedEvent event = + new ConfigChangedEvent(dataId, configInfo, getChangeType(configInfo, oldValue)); + if (configInfo == null) { + cacheData.remove(dataId); + } else { + cacheData.put(dataId, configInfo); + } + listeners.forEach(listener -> listener.process(event)); + } + + void addListener(ConfigListener configListener) { + + this.listeners.add(configListener); + } + + private ConfigChangeType getChangeType(String configInfo, String oldValue) { + if (StringUtils.isBlank(configInfo)) { + return ConfigChangeType.DELETED; + } + if (StringUtils.isBlank(oldValue)) { + return ConfigChangeType.ADDED; + } + return ConfigChangeType.MODIFIED; + } + } +} \ No newline at end of file diff --git a/config/config-nacos/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager b/config/config-nacos/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager new file mode 100644 index 000000000..c055a88ae --- /dev/null +++ b/config/config-nacos/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager @@ -0,0 +1,2 @@ +nacos=com.alipay.sofa.rpc.dynamic.nacos.NacosDynamicConfigManager + diff --git a/config/config-nacos/src/test/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManagerTest.java b/config/config-nacos/src/test/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManagerTest.java new file mode 100644 index 000000000..f880cdf7b --- /dev/null +++ b/config/config-nacos/src/test/java/com/alipay/sofa/rpc/dynamic/nacos/NacosDynamicConfigManagerTest.java @@ -0,0 +1,58 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic.nacos; + +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.DynamicHelper; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import org.junit.Assert; +import org.junit.Test; + +public class NacosDynamicConfigManagerTest { + + private final static Logger logger = LoggerFactory + .getLogger(NacosDynamicConfigManagerTest.class); + + private DynamicConfigManager nacosDynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager("test", + "nacos"); + + @Test + public void getProviderServiceProperty() { + String result = nacosDynamicConfigManager.getProviderServiceProperty("serviceName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getConsumerServiceProperty() { + String result = nacosDynamicConfigManager.getConsumerServiceProperty("serviceName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getProviderMethodProperty() { + String result = nacosDynamicConfigManager.getProviderMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getConsumerMethodProperty() { + String result = nacosDynamicConfigManager.getConsumerMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } +} \ No newline at end of file diff --git a/config/config-nacos/src/test/resources/log4j.xml b/config/config-nacos/src/test/resources/log4j.xml new file mode 100644 index 000000000..e95634f16 --- /dev/null +++ b/config/config-nacos/src/test/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/config-zk/pom.xml b/config/config-zk/pom.xml new file mode 100644 index 000000000..8701b83b0 --- /dev/null +++ b/config/config-zk/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + + + com.alipay.sofa + sofa-rpc-config + ${revision} + + + sofa-rpc-config-zk + + + + com.alipay.sofa + sofa-rpc-log-common-tools + + + com.alipay.sofa + sofa-rpc-log + + + com.alipay.sofa + sofa-rpc-api + + + + org.apache.curator + curator-framework + + + org.apache.curator + curator-x-discovery + + + org.apache.zookeeper + zookeeper + + + + org.slf4j + slf4j-log4j12 + test + + + junit + junit + test + + + + + + + src/main/java + + + src/main/resources + false + + **/** + + + + src/test/java + + + src/test/resources + false + + **/** + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.source} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-install-plugin + + ${module.install.skip} + + + + org.apache.maven.plugins + maven-deploy-plugin + + ${module.deploy.skip} + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipTests} + + + **/*Test.java + + + once + + + + + diff --git a/config/config-zk/src/main/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManager.java b/config/config-zk/src/main/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManager.java new file mode 100644 index 000000000..b1539eeb0 --- /dev/null +++ b/config/config-zk/src/main/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManager.java @@ -0,0 +1,231 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic.zk; + +import com.alipay.sofa.common.config.SofaConfigs; +import com.alipay.sofa.rpc.auth.AuthRuleGroup; +import com.alipay.sofa.rpc.common.RpcConstants; +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.dynamic.ConfigChangeType; +import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeyHelper; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicHelper; +import com.alipay.sofa.rpc.ext.Extension; +import com.alipay.sofa.rpc.listener.ConfigListener; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.*; +import org.apache.curator.retry.ExponentialBackoffRetry; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArraySet; + +import static com.alipay.sofa.common.config.SofaConfigs.getOrDefault; +import static com.alipay.sofa.rpc.common.utils.StringUtils.CONTEXT_SEP; + +/** + * @author Narziss + * @version ZookeeperDynamicConfigManager.java, v 0.1 2024年07月20日 09:23 Narziss + */ + +@Extension(value = "zookeeper", override = true) +public class ZookeeperDynamicConfigManager extends DynamicConfigManager { + + private final static Logger LOGGER = LoggerFactory + .getLogger(ZookeeperDynamicConfigManager.class); + + private final CuratorFramework zkClient; + + private final String rootPath; + private final ConcurrentMap watchListenerMap = new ConcurrentHashMap<>(); + private final ConcurrentMap configMap = new ConcurrentHashMap<>(); + + protected ZookeeperDynamicConfigManager(String appName) { + super(appName, SofaConfigs.getOrCustomDefault(DynamicConfigKeys.CONFIG_CENTER_ADDRESS, "zookeeper://127.0.0.1:2181")); + rootPath = CONTEXT_SEP + DynamicConfigKeys.CONFIG_NODE + CONTEXT_SEP + appName; + zkClient = CuratorFrameworkFactory.builder() + .connectString(getDynamicUrl().getAddress()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .namespace(DynamicConfigKeys.DEFAULT_NAMESPACE) + .build(); + zkClient.start(); + + if (!getOrDefault(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE)) { + PathChildrenCache cache = new PathChildrenCache(zkClient, rootPath, true); + cache.getListenable().addListener(new PathChildrenCacheListener() { + @Override + public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception { + switch (event.getType()) { + case CHILD_ADDED: + case CHILD_UPDATED: + String key = event.getData().getPath().substring(rootPath.length() + 1); + String value = new String(event.getData().getData()); + configMap.put(key, value); + LOGGER.info("Receive zookeeper event: " + "type=[" + event.getType() + "] key=[" + key + "] value=[" + value + "]"); + break; + case CHILD_REMOVED: + key = event.getData().getPath().substring(rootPath.length() + 1); + configMap.remove(key); + LOGGER.info("Receive zookeeper event: " + "type=[" + event.getType() + "] key=[" + key + "]"); + break; + default: + break; + } + } + }); + try { + cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); + } catch (Exception e) { + LOGGER.error("setupPathChildrenCache error", e); + } + } + } + + @Override + public void initServiceConfiguration(String service) { + // TODO 暂不支持 + } + + @Override + public void initServiceConfiguration(String service, ConfigListener listener) { + try { + String path = rootPath + CONTEXT_SEP + service; + if (zkClient.checkExists().forPath(path) != null) { + byte[] bytes = zkClient.getData().forPath(rootPath + CONTEXT_SEP + service); + String rawConfig = new String(bytes, RpcConstants.DEFAULT_CHARSET); + if (!StringUtils.isEmpty(rawConfig)) { + listener.process(new ConfigChangedEvent(service, rawConfig)); + } + } + } catch (Exception e) { + LOGGER.error("Failed to init service configuration for service: " + service, e); + } + + } + + @Override + public String getProviderServiceProperty(String service, String key) { + try { + String configValue = configMap.get(DynamicConfigKeyHelper.buildProviderServiceProKey(service, key)); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getConsumerServiceProperty(String service, String key) { + try { + String configValue = configMap.get(DynamicConfigKeyHelper.buildConsumerServiceProKey(service, key)); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getProviderMethodProperty(String service, String method, String key) { + try { + String configValue = configMap.get(DynamicConfigKeyHelper.buildProviderMethodProKey(service, method, key)); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + } + + @Override + public String getConsumerMethodProperty(String service, String method, String key) { + try { + String configValue = configMap.get(DynamicConfigKeyHelper.buildConsumerMethodProKey(service, method, key)); + return configValue != null ? configValue : DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } catch (Exception e) { + return DynamicHelper.DEFAULT_DYNAMIC_VALUE; + } + + } + + @Override + public AuthRuleGroup getServiceAuthRule(String service) { + //TODO 暂不支持 + return null; + } + + @Override + public void addListener(String key, ConfigListener listener) { + String pathKey = rootPath + CONTEXT_SEP + key; + + ZookeeperConfigListener zookeeperConfigListener = watchListenerMap.computeIfAbsent( + key, k -> createTargetListener(pathKey)); + + zookeeperConfigListener.addListener(listener); + } + + private ZookeeperConfigListener createTargetListener(String pathKey) { + ZookeeperConfigListener configListener = new ZookeeperConfigListener(pathKey); + return configListener; + } + + public class ZookeeperConfigListener implements NodeCacheListener { + + private final String pathKey; + private final Set listeners = new CopyOnWriteArraySet<>(); + private final NodeCache nodeCache; + + public ZookeeperConfigListener(String pathKey) { + this.pathKey = pathKey; + this.nodeCache = new NodeCache(zkClient, pathKey); + nodeCache.getListenable().addListener(this); + try { + nodeCache.start(); + } catch (Exception e) { + LOGGER.error("Failed to add listener for path:{}", pathKey, e); + } + } + + public void addListener(ConfigListener configListener) { + listeners.add(configListener); + } + + @Override + public void nodeChanged() throws Exception { + ChildData childData = nodeCache.getCurrentData(); + String content = null; + ConfigChangeType changeType; + if (childData == null) { + changeType = ConfigChangeType.DELETED; + + } else if (childData.getStat().getVersion() == 0) { + content = new String(childData.getData(), RpcConstants.DEFAULT_CHARSET); + changeType = ConfigChangeType.ADDED; + } else { + content = new String(childData.getData(), RpcConstants.DEFAULT_CHARSET); + changeType = ConfigChangeType.MODIFIED; + } + ConfigChangedEvent configChangeEvent = new ConfigChangedEvent(pathKey, (String) content, changeType); + listeners.forEach(listener -> listener.process(configChangeEvent)); + + } + } + + +} \ No newline at end of file diff --git a/config/config-zk/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager b/config/config-zk/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager new file mode 100644 index 000000000..5f9a8243e --- /dev/null +++ b/config/config-zk/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.dynamic.DynamicConfigManager @@ -0,0 +1 @@ +zookeeper=com.alipay.sofa.rpc.dynamic.zk.ZookeeperDynamicConfigManager diff --git a/config/config-zk/src/test/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManagerTest.java b/config/config-zk/src/test/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManagerTest.java new file mode 100644 index 000000000..9ccc3bf9f --- /dev/null +++ b/config/config-zk/src/test/java/com/alipay/sofa/rpc/dynamic/zk/ZookeeperDynamicConfigManagerTest.java @@ -0,0 +1,58 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic.zk; + +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.DynamicHelper; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import org.junit.Assert; +import org.junit.Test; + +public class ZookeeperDynamicConfigManagerTest { + + private final static Logger logger = LoggerFactory + .getLogger(ZookeeperDynamicConfigManager.class); + + private DynamicConfigManager zookeeperDynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager( + "test", "zookeeper"); + + @Test + public void getProviderServiceProperty() { + String result = zookeeperDynamicConfigManager.getProviderServiceProperty("serviceName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getConsumerServiceProperty() { + String result = zookeeperDynamicConfigManager.getConsumerServiceProperty("serviceName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getProviderMethodProperty() { + String result = zookeeperDynamicConfigManager.getProviderMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } + + @Test + public void getConsumerMethodProperty() { + String result = zookeeperDynamicConfigManager.getConsumerMethodProperty("serviceName", "methodName", "timeout"); + Assert.assertEquals(DynamicHelper.DEFAULT_DYNAMIC_VALUE, result); + } +} \ No newline at end of file diff --git a/config/config-zk/src/test/resources/log4j.xml b/config/config-zk/src/test/resources/log4j.xml new file mode 100644 index 000000000..e95634f16 --- /dev/null +++ b/config/config-zk/src/test/resources/log4j.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/pom.xml b/config/pom.xml index 7d0caacb8..2e380e67e 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -15,6 +15,8 @@ config-apollo + config-zk + config-nacos diff --git a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java index 2db6a6b1f..81d4cfa40 100644 --- a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java +++ b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AbstractCluster.java @@ -689,7 +689,7 @@ private SofaResponse buildEmptyResponse(SofaRequest request) { * @return 调用超时 */ private int resolveTimeout(SofaRequest request, ConsumerConfig consumerConfig, ProviderInfo providerInfo) { - // 动态配置优先 + // 请求级别动态配置优先 final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS); if (StringUtils.isNotBlank(dynamicAlias)) { String dynamicTimeout = null; @@ -707,6 +707,7 @@ private int resolveTimeout(SofaRequest request, ConsumerConfig consumerConfig, P return Integer.parseInt(dynamicTimeout); } } + // 先去调用级别配置 Integer timeout = request.getTimeout(); if (timeout == null || timeout <= 0) { diff --git a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/lb/AutoLoadBalancer.java b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/lb/AutoLoadBalancer.java index 9bf01c75e..27d92a90d 100644 --- a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/lb/AutoLoadBalancer.java +++ b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/lb/AutoLoadBalancer.java @@ -53,7 +53,7 @@ public AutoLoadBalancer(ConsumerBootstrap consumerBootstrap) { @Override protected ProviderInfo doSelect(SofaRequest request, List providerInfos) { - // 动态配置优先 + // 请求级别动态配置优先 final String dynamicAlias = consumerConfig.getParameter(DynamicConfigKeys.DYNAMIC_ALIAS); if (StringUtils.isNotBlank(dynamicAlias)) { String dynamicLoadBalancer = null; diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java index acc4a74e1..f3a236e09 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/AbstractInterfaceConfig.java @@ -215,6 +215,11 @@ public abstract class AbstractInterfaceConfig configValueCache = null; + /** + * 动态配置的方法名称和方法参数配置的map + */ + protected transient volatile Map dynamicConfigValueCache = new ConcurrentHashMap<>(); + /** * 代理接口类,和T对应,主要针对泛化调用 */ @@ -703,6 +708,15 @@ public Map getConfigValueCache() { return configValueCache; } + /** + * Gets dynamic config value cache. + * + * @return the dynamic config value cache + */ + public Map getDynamicConfigValueCache() { + return dynamicConfigValueCache; + } + /** * Sets config listener. * @@ -930,7 +944,7 @@ public boolean updateAttribute(String property, String newValueStr, boolean over int index = methodAndP.indexOf(RpcConstants.HIDE_KEY_PREFIX); if (index <= 0) { throw ExceptionUtils.buildRuntime(property, newValueStr, - "Unknown update attribute key!"); + "Unknown update attribute key!"); } String methodName = methodAndP.substring(0, index); String methodProperty = methodAndP.substring(index + 1); @@ -940,6 +954,9 @@ public boolean updateAttribute(String property, String newValueStr, boolean over // 拿到旧的值 Object oldValue = null; Object newValue = CompatibleTypeUtils.convert(newValueStr, propertyClazz); + if (dynamicConfigValueCache.containsKey(property)) { + dynamicConfigValueCache.put(property, newValue); + } if (methodConfig == null) { methodConfig = new MethodConfig(); methodConfig.setName(methodName); @@ -962,7 +979,7 @@ public boolean updateAttribute(String property, String newValueStr, boolean over BeanUtils.setProperty(methodConfig, methodProperty, propertyClazz, newValue);// 覆盖属性 if (LOGGER.isInfoEnabled()) { LOGGER.info("Property \"" + methodName + "." + methodProperty + "\" changed from {} to {}", - oldValue, newValueStr); + oldValue, newValueStr); } } } else { // 接口级配置 例如timeout @@ -972,6 +989,9 @@ public boolean updateAttribute(String property, String newValueStr, boolean over // 拿到旧的值 Object oldValue = BeanUtils.getProperty(this, property, propertyClazz); Object newValue = CompatibleTypeUtils.convert(newValueStr, propertyClazz); + if (dynamicConfigValueCache.containsKey(property)) { + dynamicConfigValueCache.put(property, newValue); + } if (oldValue == null) { if (newValueStr != null) { changed = true; @@ -991,7 +1011,7 @@ public boolean updateAttribute(String property, String newValueStr, boolean over throw e; } catch (Exception e) { throw new SofaRpcRuntimeException(LogCodes.getLog(LogCodes.ERROR_UPDATE_ATTRIBUTE, property, newValueStr), - e); + e); } } @@ -1016,11 +1036,17 @@ public Object getMethodConfigValue(String methodName, String configKey, Object d * @return 配置值 method config value */ public Object getMethodConfigValue(String methodName, String configKey) { - if (configValueCache == null) { - return null; - } String key = buildmkey(methodName, configKey); - return configValueCache.get(key); + Object value = null; + if (dynamicConfigValueCache != null) { + value = dynamicConfigValueCache.get(key); + } + if (value == null) { + if (configValueCache != null) { + value = configValueCache.get(key); + } + } + return value; } /** diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangeType.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangeType.java new file mode 100644 index 000000000..99f87d457 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangeType.java @@ -0,0 +1,39 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic; + +/** + * @author Narziss + * @version ConfigChangeType.java, v 0.1 2024年09月15日 20:20 Narziss + */ + +public enum ConfigChangeType { + /** + * A config is created. + */ + ADDED, + + /** + * A config is updated. + */ + MODIFIED, + + /** + * A config is deleted. + */ + DELETED +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangedEvent.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangedEvent.java new file mode 100644 index 000000000..220f2889d --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/ConfigChangedEvent.java @@ -0,0 +1,88 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic; + +import com.alipay.sofa.rpc.common.utils.StringUtils; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; + +import java.util.EventObject; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Narziss + * @version ConfigChangedEvent.java, v 0.1 2024年09月15日 20:12 Narziss + */ + +public class ConfigChangedEvent extends EventObject { + + private final static Logger LOGGER = LoggerFactory.getLogger(ConfigChangedEvent.class); + + private final String key; + + private final String content; + + private final ConfigChangeType changeType; + + private final Map dynamicValueMap = new HashMap<>(); + + public ConfigChangedEvent(String key, String content) { + this(key, content, ConfigChangeType.MODIFIED); + } + + public ConfigChangedEvent(String key, String content, ConfigChangeType changeType) { + super(key); + this.key = key; + this.content = content; + this.changeType = changeType; + if (StringUtils.isNotBlank(content)) { + parseConfigurationLines(content); + } + } + + private void parseConfigurationLines(String content) { + String[] lines = content.split(System.lineSeparator()); + for (String line : lines) { + String[] keyValue = line.split("=", 2); + if (keyValue.length == 2) { + String mapKey = keyValue[0].trim(); + String mapValue = keyValue[1].trim(); + dynamicValueMap.put(mapKey, mapValue); + } else { + LOGGER.warn("Malformed configuration line: {}", line); + } + } + } + + public String getKey() { + return key; + } + + public String getContent() { + return content; + } + + public ConfigChangeType getChangeType() { + return changeType; + } + + public Map getDynamicValueMap() { + return dynamicValueMap; + } + +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigKeys.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigKeys.java index d8c49dcec..44bb51901 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigKeys.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigKeys.java @@ -16,10 +16,33 @@ */ package com.alipay.sofa.rpc.dynamic; +import com.alipay.sofa.common.config.ConfigKey; + /** * @author bystander * @version : DynamicConfigKeys.java, v 0.1 2019年04月17日 21:51 bystander Exp $ */ public class DynamicConfigKeys { - public static final String DYNAMIC_ALIAS = "dynamicAlias"; + public static final String DYNAMIC_ALIAS = "dynamicAlias"; + + public static final String CONFIG_NODE = "config"; + + public static final String DEFAULT_NAMESPACE = "sofa-rpc"; + + public static ConfigKey CONFIG_CENTER_ADDRESS = ConfigKey + .build( + "sofa.rpc.config.center.address", + " ", + false, + "The url of the dynamic configuration.", + new String[] { "sofa_rpc_config_center_address" }); + + public static ConfigKey DYNAMIC_REFRESH_ENABLE = ConfigKey + .build( + "sofa.rpc.config.dynamic.refresh.enable", + false, + false, + "Switch for dynamic configuration refresh.", + new String[] { "sofa_rpc_config_dynamic_refresh_enable" }); + } \ No newline at end of file diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManager.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManager.java index f44818df8..8c7ac5fa6 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManager.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManager.java @@ -17,22 +17,40 @@ package com.alipay.sofa.rpc.dynamic; import com.alipay.sofa.rpc.auth.AuthRuleGroup; +import com.alipay.sofa.rpc.common.utils.StringUtils; import com.alipay.sofa.rpc.ext.Extensible; +import com.alipay.sofa.rpc.listener.ConfigListener; /** - * * @author bystander * @version : DynamicManager.java, v 0.1 2019年04月12日 11:35 bystander Exp $ */ @Extensible(singleton = true) public abstract class DynamicConfigManager { - private String appName; + private String appName; + + private DynamicUrl dynamicUrl; protected DynamicConfigManager(String appName) { this.appName = appName; } + protected DynamicConfigManager(String appName, String configCenterAddress) { + this.appName = appName; + if (StringUtils.isNotBlank(configCenterAddress)) { + this.dynamicUrl = new DynamicUrl(configCenterAddress); + } + } + + protected String getAppName() { + return appName; + } + + protected DynamicUrl getDynamicUrl() { + return dynamicUrl; + } + /** * Init service's governance related configuration. * Such as auth rules、lb rules @@ -41,11 +59,21 @@ protected DynamicConfigManager(String appName) { */ public abstract void initServiceConfiguration(String service); + /** + * Init service's governance related configuration. + * Such as auth rules、lb rules + * + * @param service target service + * @param listener config listener + */ + public void initServiceConfiguration(String service, ConfigListener listener) { + } + /** * Get provider service related property. * * @param service target service - * @param key property key + * @param key property key * @return property value */ public abstract String getProviderServiceProperty(String service, String key); @@ -54,7 +82,7 @@ protected DynamicConfigManager(String appName) { * Get consumer service related property. * * @param service target service - * @param key property key + * @param key property key * @return property value */ public abstract String getConsumerServiceProperty(String service, String key); @@ -63,8 +91,8 @@ protected DynamicConfigManager(String appName) { * Get provider method related property. * * @param service target service - * @param method target method - * @param key property key + * @param method target method + * @param key property key * @return property value */ public abstract String getProviderMethodProperty(String service, String method, String key); @@ -73,8 +101,8 @@ protected DynamicConfigManager(String appName) { * Get consumer method related property. * * @param service target service - * @param method target method - * @param key property key + * @param method target method + * @param key property key * @return property value */ public abstract String getConsumerMethodProperty(String service, String method, String key); @@ -86,4 +114,14 @@ protected DynamicConfigManager(String appName) { * @return auth rules */ public abstract AuthRuleGroup getServiceAuthRule(String service); + + /** + * Add config listener. + * + * @param key config key + * @param listener config listener + */ + public void addListener(String key, ConfigListener listener) { + } + } \ No newline at end of file diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java index d3cee7245..5b29646f2 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicConfigManagerFactory.java @@ -51,7 +51,7 @@ public class DynamicConfigManagerFactory { .getLogger(DynamicConfigManagerFactory.class); /** - * 得到动态配置管理 + * 得到动态配置管理器 * * @param alias 别名 * @return DynamicManager 实现 diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicUrl.java b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicUrl.java new file mode 100644 index 000000000..b83ffc3d7 --- /dev/null +++ b/core/api/src/main/java/com/alipay/sofa/rpc/dynamic/DynamicUrl.java @@ -0,0 +1,102 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic; + +import java.util.Map; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Narziss + * @version DynamicUrl.java, v 0.1 2024年10月28日 21:23 Narziss + */ +public class DynamicUrl { + + private final String originalUrl; + private final String protocol; + private final String address; + private final String host; + private final int port; + private final String path; + private final Map params = new HashMap<>(); + + /** + * @param configCenterAddress example: apollo://127.0.0.1:8080/config?appId=xxx&cluster=yyy + */ + public DynamicUrl(String configCenterAddress) { + this.originalUrl = configCenterAddress; + // 正则表达式解析协议、主机、端口、路径和参数,其中路径和参数是可选的 + String regex = "^(\\w+)://([^:/]+):(\\d+)(/[^?]*)?(\\?.*)?$"; + Matcher matcher = Pattern.compile(regex).matcher(configCenterAddress); + if (matcher.find()) { + this.protocol = matcher.group(1); + this.host = matcher.group(2); + this.port = Integer.parseInt(matcher.group(3)); + // 判断路径是否为空或者为 "/" + this.path = (matcher.group(4) != null && !matcher.group(4).equals("/")) ? matcher.group(4) : ""; + this.address = this.host + ":" + this.port + this.path; + if (matcher.group(5) != null) { + parseQueryParams(matcher.group(5).substring(1)); + } + } else { + throw new IllegalArgumentException("Invalid URL format"); + } + } + + private void parseQueryParams(String query) { + String[] paramPairs = query.split("&"); + for (String paramPair : paramPairs) { + String[] keyValue = paramPair.split("=", 2); + if (keyValue.length == 2) { + params.put(keyValue[0], keyValue[1]); + } + } + } + + public String getOriginalUrl() { + return originalUrl; + } + + public String getProtocol() { + return protocol; + } + + public String getAddress() { + return address; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getPath() { + return path; + } + + public Map getParams() { + return params; + } + + public String getParam(String key) { + return params.get(key); + } +} diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/listener/ConfigListener.java b/core/api/src/main/java/com/alipay/sofa/rpc/listener/ConfigListener.java index 7fb03ac2b..0c7685350 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/listener/ConfigListener.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/listener/ConfigListener.java @@ -16,6 +16,8 @@ */ package com.alipay.sofa.rpc.listener; +import com.alipay.sofa.rpc.dynamic.ConfigChangedEvent; + import java.util.Map; /** @@ -25,6 +27,15 @@ */ public interface ConfigListener { + /** + * 处理配置变更事件 + * + * @param event 配置变更事件 + */ + default void process(ConfigChangedEvent event){ + // do nothing + } + /** * 配置发生变化,例如 * diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/dynamic/DynamicUrlTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/dynamic/DynamicUrlTest.java new file mode 100644 index 000000000..86f2cd187 --- /dev/null +++ b/core/api/src/test/java/com/alipay/sofa/rpc/dynamic/DynamicUrlTest.java @@ -0,0 +1,79 @@ +/* + * 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 com.alipay.sofa.rpc.dynamic; + +import org.junit.Test; +import org.junit.Assert; + +/** + * @author Narziss + * @version DynamicUrl.java, v 0.1 2024年10月28日 21:40 Narziss + */ +public class DynamicUrlTest { + + @Test + public void testWithPathAndParams() { + DynamicUrl dynamicUrl = new DynamicUrl("apollo://127.0.0.1:8080/config?appId=xxx&cluster=yyy"); + Assert.assertEquals("apollo", dynamicUrl.getProtocol()); + Assert.assertEquals("127.0.0.1", dynamicUrl.getHost()); + Assert.assertEquals(8080, dynamicUrl.getPort()); + Assert.assertEquals("/config", dynamicUrl.getPath()); + Assert.assertEquals("127.0.0.1:8080/config", dynamicUrl.getAddress()); + Assert.assertNotNull(dynamicUrl.getParams()); + Assert.assertEquals("xxx", dynamicUrl.getParams().get("appId")); + Assert.assertEquals("yyy", dynamicUrl.getParams().get("cluster")); + } + + @Test + public void testWithSlashAndParams() { + DynamicUrl dynamicUrl = new DynamicUrl("apollo://127.0.0.1:8080/?appId=xxx&cluster=yyy"); + Assert.assertEquals("apollo", dynamicUrl.getProtocol()); + Assert.assertEquals("127.0.0.1", dynamicUrl.getHost()); + Assert.assertEquals(8080, dynamicUrl.getPort()); + Assert.assertEquals("", dynamicUrl.getPath());// 如果路径为空,返回空字符串 + Assert.assertEquals("127.0.0.1:8080", dynamicUrl.getAddress()); + Assert.assertNotNull(dynamicUrl.getParams()); + Assert.assertEquals("xxx", dynamicUrl.getParams().get("appId")); + Assert.assertEquals("yyy", dynamicUrl.getParams().get("cluster")); + } + + @Test + public void testWithParams() { + DynamicUrl dynamicUrl = new DynamicUrl("apollo://127.0.0.1:8080?appId=xxx&cluster=yyy"); + Assert.assertEquals("apollo", dynamicUrl.getProtocol()); + Assert.assertEquals("127.0.0.1", dynamicUrl.getHost()); + Assert.assertEquals(8080, dynamicUrl.getPort()); + Assert.assertEquals("", dynamicUrl.getPath()); + Assert.assertEquals("127.0.0.1:8080", dynamicUrl.getAddress()); + Assert.assertNotNull(dynamicUrl.getParams()); + Assert.assertEquals("xxx", dynamicUrl.getParams().get("appId")); + Assert.assertEquals("yyy", dynamicUrl.getParams().get("cluster")); + } + + @Test + public void testOnlyHostAndPort() { + DynamicUrl dynamicUrl = new DynamicUrl("apollo://127.0.0.1:8080"); + Assert.assertEquals("apollo", dynamicUrl.getProtocol()); + Assert.assertEquals("127.0.0.1", dynamicUrl.getHost()); + Assert.assertEquals(8080, dynamicUrl.getPort()); + Assert.assertEquals("", dynamicUrl.getPath()); + Assert.assertEquals("127.0.0.1:8080", dynamicUrl.getAddress()); + System.out.println(dynamicUrl.getParams()); + Assert.assertNotNull(dynamicUrl.getParams()); + Assert.assertTrue(dynamicUrl.getParams().isEmpty()); + } +} diff --git a/test/test-integration/pom.xml b/test/test-integration/pom.xml index 87aef8ddc..6e3d254a3 100644 --- a/test/test-integration/pom.xml +++ b/test/test-integration/pom.xml @@ -201,7 +201,7 @@ com.alipay.sofa - sofa-rpc-config-apollo + sofa-rpc-config-nacos ${project.parent.version} test @@ -261,6 +261,24 @@ junit test + + com.alipay.sofa + sofa-rpc-config-apollo + ${project.parent.version} + test + + + com.alipay.sofa + sofa-rpc-config-zk + ${project.parent.version} + test + + + org.apache.curator + curator-test + 4.3.0 + test + diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ApolloDynamicConfigTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ApolloDynamicConfigTest.java new file mode 100644 index 000000000..4a9bbf20f --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ApolloDynamicConfigTest.java @@ -0,0 +1,97 @@ +/* + * 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 com.alipay.sofa.rpc.test.config; + +import com.alipay.sofa.rpc.config.ApplicationConfig; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.apollo.ApolloDynamicConfigManager; +import com.alipay.sofa.rpc.test.HelloService; +import com.ctrip.framework.apollo.enums.PropertyChangeType; +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Narziss + * @version ApolloDynamicConfigTest.java, v 0.1 2024年09月28日 10:46 Narziss + */ +public class ApolloDynamicConfigTest { + + @Test + public void testApolloDynamicConfig() throws Exception { + System.setProperty(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE.getKey(), "true"); + System.setProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey(), "apollo://127.0.0.1:8080?appId=demo"); + ApplicationConfig clientApplication = new ApplicationConfig(); + clientApplication.setAppName("demo"); + + ConsumerConfig consumerConfig = new ConsumerConfig() + .setInterfaceId(HelloService.class.getName()) + .setProtocol("bolt") + .setDirectUrl("bolt://127.0.0.1:12200") + .setConnectTimeout(10 * 1000) + .setApplication(clientApplication); + + consumerConfig.refer(); + + // 获取接口对应的动态配置监听器 + DynamicConfigManager dynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager + (clientApplication.getAppName(), "apollo"); + Field field = ApolloDynamicConfigManager.class.getDeclaredField("watchListenerMap"); + field.setAccessible(true); + Map watchListenerMap = (Map) field + .get(dynamicConfigManager); + ApolloDynamicConfigManager.ApolloListener apolloConfigListener = watchListenerMap.get(consumerConfig + .getInterfaceId()); + + // 测试配置新增 + String configValue = "timeout=5000"+System.lineSeparator(); + ConfigChange configChange = new ConfigChange("application", consumerConfig.getInterfaceId(), null, configValue, PropertyChangeType.ADDED); + Map changes = new HashMap<>(); + changes.put(configChange.getPropertyName(), configChange); + ConfigChangeEvent event = new ConfigChangeEvent("application", changes); + apolloConfigListener.onChange(event); + Assert.assertEquals(5000, consumerConfig.getMethodTimeout("sayHello")); + + // 测试配置修改 + String oldValue = configValue; + configValue = "timeout=5000"+System.lineSeparator()+".sayHello.timeout=6000"; + configChange = new ConfigChange("application", consumerConfig.getInterfaceId(), oldValue, configValue, PropertyChangeType.MODIFIED); + changes = new HashMap<>(); + changes.put(configChange.getPropertyName(), configChange); + event = new ConfigChangeEvent("application", changes); + apolloConfigListener.onChange(event); + Assert.assertEquals(6000, consumerConfig.getMethodTimeout("sayHello")); + + // 测试配置删除 + configChange = new ConfigChange("application", consumerConfig.getInterfaceId(), configValue, null, PropertyChangeType.DELETED); + changes = new HashMap<>(); + changes.put(configChange.getPropertyName(), configChange); + event = new ConfigChangeEvent("application", changes); + apolloConfigListener.onChange(event); + Assert.assertEquals(-1, consumerConfig.getMethodTimeout("sayHello")); + + System.clearProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey()); + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/NacosDynamicConfigTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/NacosDynamicConfigTest.java new file mode 100644 index 000000000..4a2b281fc --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/NacosDynamicConfigTest.java @@ -0,0 +1,81 @@ +/* + * 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 com.alipay.sofa.rpc.test.config; + +import com.alipay.sofa.rpc.config.ApplicationConfig; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; + +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.nacos.NacosDynamicConfigManager; +import com.alipay.sofa.rpc.test.HelloService; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.Map; + +/** + * @author Narziss + * @version NacosDynamicConfigTest.java, v 0.1 2024年09月28日 12:11 Narziss + */ +public class NacosDynamicConfigTest { + + @Test + public void testNacosDynamicConfig() throws Exception { + System.setProperty(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE.getKey(), "true"); + System.setProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey(), + "nacos://127.0.0.1:8848/sofa-rpc-config?username=nacos&password=nacos"); + ApplicationConfig clientApplication = new ApplicationConfig(); + clientApplication.setAppName("demo"); + + ConsumerConfig consumerConfig = new ConsumerConfig() + .setInterfaceId(HelloService.class.getName()) + .setProtocol("bolt") + .setDirectUrl("bolt://127.0.0.1:12200") + .setConnectTimeout(10 * 1000) + .setApplication(clientApplication); + + consumerConfig.refer(); + + // 获取接口对应的动态配置监听器 + DynamicConfigManager dynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager + (clientApplication.getAppName(), "nacos"); + Field field = NacosDynamicConfigManager.class.getDeclaredField("watchListenerMap"); + field.setAccessible(true); + Map watchListenerMap = (Map) field + .get(dynamicConfigManager); + NacosDynamicConfigManager.NacosConfigListener nacosConfigListener = watchListenerMap.get(consumerConfig + .getInterfaceId()); + + // 测试配置新增 + String configValue = "timeout=5000"; + nacosConfigListener.innerReceive(consumerConfig.getInterfaceId(), consumerConfig.getAppName(), configValue); + Assert.assertEquals(5000, consumerConfig.getMethodTimeout("sayHello")); + // 测试配置修改 + configValue = "timeout=5000" + System.lineSeparator() + ".sayHello.timeout=6000"; + nacosConfigListener.innerReceive(consumerConfig.getInterfaceId(), consumerConfig.getAppName(), configValue); + Assert.assertEquals(6000, consumerConfig.getMethodTimeout("sayHello")); + // 测试配置删除 + configValue = ""; + nacosConfigListener.innerReceive(consumerConfig.getInterfaceId(), consumerConfig.getAppName(), configValue); + Assert.assertEquals(-1, consumerConfig.getMethodTimeout("sayHello")); + + System.clearProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey()); + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ZookeeperDynamicConfigTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ZookeeperDynamicConfigTest.java new file mode 100644 index 000000000..a67916e07 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/ZookeeperDynamicConfigTest.java @@ -0,0 +1,97 @@ +/* + * 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 com.alipay.sofa.rpc.test.config; + +import com.alipay.sofa.rpc.config.ApplicationConfig; +import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.dynamic.DynamicConfigKeys; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManager; +import com.alipay.sofa.rpc.dynamic.DynamicConfigManagerFactory; +import com.alipay.sofa.rpc.dynamic.zk.ZookeeperDynamicConfigManager; +import com.alipay.sofa.rpc.log.Logger; +import com.alipay.sofa.rpc.log.LoggerFactory; +import com.alipay.sofa.rpc.test.HelloService; +import com.alipay.sofa.rpc.test.config.base.BaseZkTest; +import org.apache.curator.framework.CuratorFramework; +import org.apache.zookeeper.CreateMode; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Field; + +/** + * @author Narziss + * @version ZookeeperDynamicConfigTest.java, v 0.1 2024年09月28日 14:33 Narziss + */ +public class ZookeeperDynamicConfigTest extends BaseZkTest { + + Logger logger = LoggerFactory.getLogger(ZookeeperDynamicConfigTest.class); + + @Test + public void testZookeeperDynamicConfig() throws Exception { + System.setProperty(DynamicConfigKeys.DYNAMIC_REFRESH_ENABLE.getKey(), "true"); + System.setProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey(), "zookeeper://127.0.0.1:2181"); + ApplicationConfig clientApplication = new ApplicationConfig(); + clientApplication.setAppName("demo"); + + ConsumerConfig consumerConfig = new ConsumerConfig() + .setInterfaceId(HelloService.class.getName()) + .setProtocol("bolt") + .setDirectUrl("bolt://127.0.0.1:12200") + .setConnectTimeout(10 * 1000) + .setApplication(clientApplication); + + consumerConfig.refer(); + + DynamicConfigManager dynamicConfigManager = DynamicConfigManagerFactory.getDynamicManager + (clientApplication.getAppName(), "zookeeper"); + Field field = ZookeeperDynamicConfigManager.class.getDeclaredField("zkClient"); + field.setAccessible(true); + CuratorFramework zkClient = (CuratorFramework) field.get(dynamicConfigManager); + + // 新增或修改配置节点 + if (zkClient.checkExists().forPath("/config/demo/com.alipay.sofa.rpc.test.HelloService") == null) { + zkClient.create() + .creatingParentsIfNeeded() + .withMode(CreateMode.PERSISTENT) + .forPath("/config/demo/com.alipay.sofa.rpc.test.HelloService", "timeout=5000".getBytes()); + } else { + zkClient.setData().forPath("/config/demo/com.alipay.sofa.rpc.test.HelloService", + "timeout=5000".getBytes()); + } + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + // 验证配置是否更新 + Assert.assertEquals(5000, consumerConfig.getMethodTimeout("sayHello")); + + //删除配置节点 + zkClient.delete().forPath("/config/demo/com.alipay.sofa.rpc.test.HelloService"); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + // 验证配置是否删除 + Assert.assertEquals(-1, consumerConfig.getMethodTimeout("sayHello")); + + System.clearProperty(DynamicConfigKeys.CONFIG_CENTER_ADDRESS.getKey()); + + } +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/base/BaseZkTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/base/BaseZkTest.java new file mode 100644 index 000000000..9268a8f0b --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/config/base/BaseZkTest.java @@ -0,0 +1,62 @@ +/* + * 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 com.alipay.sofa.rpc.test.config.base; + +import com.alipay.sofa.rpc.context.RpcInternalContext; +import com.alipay.sofa.rpc.context.RpcInvokeContext; +import com.alipay.sofa.rpc.context.RpcRunningState; +import com.alipay.sofa.rpc.context.RpcRuntimeContext; +import org.apache.curator.test.TestingServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.io.IOException; + +/** + * @author Narziss + * @version BaseZkTest.java, v 0.1 2024年10月08日 10:20 Narziss + */ +public abstract class BaseZkTest { + protected static TestingServer server = null; + + @BeforeClass + public static void adBeforeClass() { + RpcRunningState.setUnitTestMode(true); + + try { + server = new TestingServer(2181, true); + server.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void adAfterClass() { + RpcRuntimeContext.destroy(); + RpcInternalContext.removeContext(); + RpcInvokeContext.removeContext(); + + if (server != null) { + try { + server.stop(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file From be93251f7ac754178811dd04d826ebe8f0967a1a Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 1 Nov 2024 18:34:18 +0800 Subject: [PATCH 61/64] release rpc version 5.14.0-SNAPSHOT (#1458) Co-authored-by: liujianjun.ljj --- all/pom.xml | 2 +- bom/pom.xml | 2 +- .../src/main/java/com/alipay/sofa/rpc/common/Version.java | 6 +++--- pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 3351476d9..a35795632 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -6,7 +6,7 @@ com.alipay.sofa sofa-rpc-all - 5.13.2 + 5.14.0-SNAPSHOT ${project.groupId}:${project.artifactId} diff --git a/bom/pom.xml b/bom/pom.xml index 7a79b1b1b..799d598dd 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -10,7 +10,7 @@ pom - 5.13.2 + 5.14.0-SNAPSHOT 3.29.2-GA 1.9.8 4.1.77.Final diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java index ca8533b36..388f0ce58 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/Version.java @@ -27,16 +27,16 @@ public final class Version { /** * 当前RPC版本,例如:5.6.7 */ - public static final String VERSION = "5.13.2"; + public static final String VERSION = "5.14.0"; /** * 当前RPC版本,例如: 5.6.7 对应 50607 */ - public static final int RPC_VERSION = 51302; + public static final int RPC_VERSION = 51400; /** * 当前Build版本,每次发布修改 */ - public static final String BUILD_VERSION = "5.13.2_20241016193119"; + public static final String BUILD_VERSION = "5.14.0_20241101180137"; } diff --git a/pom.xml b/pom.xml index d9329de5f..e3671ef3c 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ - 5.13.2 + 5.14.0-SNAPSHOT 1.33 true true From 5fc75a293ff9fede32ba7c3b24975cea3f4485c5 Mon Sep 17 00:00:00 2001 From: Just-CJ Date: Fri, 14 Mar 2025 11:35:36 +0800 Subject: [PATCH 62/64] fix: hessian deserialize support sofa.serialize.dynamic.load.enable (#1463) --- ...ingleClassLoaderSofaSerializerFactory.java | 29 ++++++++++++--- ...eClassLoaderSofaSerializerFactoryTest.java | 35 +++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactory.java b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactory.java index d79ddf610..8e0a8489c 100644 --- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactory.java +++ b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactory.java @@ -27,6 +27,9 @@ import com.caucho.hessian.io.Serializer; import com.caucho.hessian.io.SerializerFactory; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import static com.alipay.hessian.generic.io.GenericDeserializer.ARRAY_PREFIX; import static com.alipay.sofa.rpc.codec.sofahessian.serialize.GenericCustomThrowableDeterminer.isGenericThrowException; @@ -40,8 +43,14 @@ public class SingleClassLoaderSofaSerializerFactory extends SerializerFactory { /** * logger for this class */ - private static final Logger LOGGER = LoggerFactory - .getLogger(SingleClassLoaderSofaSerializerFactory.class); + private static final Logger LOGGER = LoggerFactory + .getLogger(SingleClassLoaderSofaSerializerFactory.class); + + private final Map> _typeNotFoundMap = new ConcurrentHashMap<>(8); + private static final Object NOT_FOUND = new Object(); + private final boolean dynamicLoadEnable = Boolean.parseBoolean(System.getProperty( + DYNAMIC_LOAD_ENABLE_KEY, + Boolean.FALSE.toString())); @Override protected Serializer getDefaultSerializer(Class cl) { @@ -73,14 +82,24 @@ public Deserializer getDeserializer(String type) throws HessianProtocolException Deserializer subDeserializer = getDeserializer(type.substring(1)); deserializer = new ArrayDeserializer(subDeserializer); } else { + ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader(); try { - ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader(); + if (!dynamicLoadEnable) { + Map typeMap = _typeNotFoundMap.get(appClassLoader); + if (typeMap != null) { + if (typeMap.containsKey(type)) { + return null; + } + } + } Class cl = Class.forName(type, true, appClassLoader); deserializer = getDeserializer(cl); } catch (Exception e) { if (e instanceof ClassNotFoundException) { - LOGGER.errorWithApp(null, LogCodes.getLog(LogCodes.ERROR_DECODE_CLASS_NOT_FOUND, - getClass().getName(), type, Thread.currentThread().getContextClassLoader())); + if (!dynamicLoadEnable) { + _typeNotFoundMap.computeIfAbsent(appClassLoader, k -> new ConcurrentHashMap<>(8)).put(type, NOT_FOUND); + } + LOGGER.errorWithApp(null, LogCodes.getLog(LogCodes.ERROR_DECODE_CLASS_NOT_FOUND, getClass().getName(), type, appClassLoader)); } else { LOGGER.errorWithApp(null, e.toString(), e); } diff --git a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactoryTest.java b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactoryTest.java index 727f1ff0b..26bef4434 100644 --- a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactoryTest.java +++ b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/SingleClassLoaderSofaSerializerFactoryTest.java @@ -16,13 +16,17 @@ */ package com.alipay.sofa.rpc.codec.sofahessian; +import com.caucho.hessian.io.Deserializer; import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; +import com.caucho.hessian.io.SerializerFactory; +import org.junit.Assert; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -63,4 +67,35 @@ public void testAll() throws IOException { assertEquals(a1[i], a2[i]); } + @Test + public void testDynamicLoadDisabled() throws Exception { + SingleClassLoaderSofaSerializerFactory factory = new SingleClassLoaderSofaSerializerFactory(); + Field field = SingleClassLoaderSofaSerializerFactory.class.getDeclaredField("_typeNotFoundMap"); + field.setAccessible(true); + Map> _typeNotFoundMap = (Map>) field + .get(factory); + Assert.assertEquals(0, _typeNotFoundMap.size()); + Deserializer deserializer = factory.getDeserializer("mock.xxx.MockObject"); + Assert.assertNull(deserializer); + Assert.assertEquals(1, _typeNotFoundMap.size()); + } + + @Test + public void testDynamicLoadEnabled() throws Exception { + try { + System.setProperty(SerializerFactory.DYNAMIC_LOAD_ENABLE_KEY, "true"); + SingleClassLoaderSofaSerializerFactory factory = new SingleClassLoaderSofaSerializerFactory(); + Field field = SingleClassLoaderSofaSerializerFactory.class.getDeclaredField("_typeNotFoundMap"); + field.setAccessible(true); + Map> _typeNotFoundMap = (Map>) field + .get(factory); + Assert.assertEquals(0, _typeNotFoundMap.size()); + Deserializer deserializer = factory.getDeserializer("mock.xxx.MockObject"); + Assert.assertNull(deserializer); + Assert.assertEquals(0, _typeNotFoundMap.size()); + } finally { + System.clearProperty(SerializerFactory.DYNAMIC_LOAD_ENABLE_KEY); + } + } + } \ No newline at end of file From 7d1a0527e42164e205b0d2eb75d67dbfb97a6378 Mon Sep 17 00:00:00 2001 From: evenliu Date: Fri, 14 Mar 2025 11:35:52 +0800 Subject: [PATCH 63/64] fix the triple header context transfer issue (#1467) * fix triple header and usedId problem * Increase the extensibility of the header conversion context. * fix the triple header context transfer issue --------- Co-authored-by: liujianjun.ljj --- .../ServerReqHeaderInterceptor.java | 23 +++++++++++++------ .../tracer/sofatracer/TracingContextKey.java | 6 +++++ .../sofatracer/TripleTracerAdapter.java | 23 ++++++++++++++++++- .../sofatracer/TripleTracerAdapterTest.java | 10 ++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java index b531ae5de..20c57990c 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java @@ -62,14 +62,8 @@ public ServerCall.Listener interceptCall(final ServerCall Context convertHeaderToContext(ServerCall call, + Metadata requestHeaders, SofaRequest sofaRequest, + ServerServiceDefinition serverServiceDefinition) { + TripleTracerAdapter.serverReceived(sofaRequest, serverServiceDefinition, call, requestHeaders); + String userId = TripleTracerAdapter.getUserId(requestHeaders); + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + SofaTracerSpan serverSpan = sofaTraceContext.getCurrentSpan(); + return Context.current() + .withValue(TracingContextKey.getKey(), serverSpan) + .withValue(TracingContextKey.getSpanContextKey(), serverSpan.context()) + .withValue(TracingContextKey.getKeySofaRequest(), sofaRequest) + .withValue(TracingContextKey.getKeyMetadata(), requestHeaders) + .withValue(TracingContextKey.getKeyUserId(), userId); + } } \ No newline at end of file diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TracingContextKey.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TracingContextKey.java index f07252b6e..507c06f1b 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TracingContextKey.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TracingContextKey.java @@ -31,6 +31,8 @@ public class TracingContextKey { public static final String KEY_SOFA_REQUEST_NAME = "io.opentracing.sofa-request"; private static final Context.Key keySofaRequest = Context.key(KEY_SOFA_REQUEST_NAME); private static final Context.Key keyMetadata = Context.key("io.opentracing.metadata"); + public static final String KEY_TRIPLE_USER_ID = "io.opentracing.tri-user-id"; + private static final Context.Key keyUserId = Context.key(KEY_TRIPLE_USER_ID); /** * Retrieves the active span. @@ -70,4 +72,8 @@ public static Context.Key getKeySofaRequest() { public static Context.Key getKeyMetadata() { return keyMetadata; } + + public static Context.Key getKeyUserId() { + return keyUserId; + } } diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java index e17af6406..50800b934 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java @@ -16,6 +16,8 @@ */ package com.alipay.sofa.rpc.tracer.sofatracer; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; import com.alipay.common.tracer.core.appender.self.SelfLog; import com.alipay.common.tracer.core.context.span.SofaTracerSpanContext; import com.alipay.common.tracer.core.context.trace.SofaTraceContext; @@ -51,6 +53,7 @@ import java.util.Set; import static com.alipay.sofa.rpc.common.RemotingConstants.HEAD_APP_NAME; +import static com.alipay.sofa.rpc.server.triple.TripleHeadKeys.HEAD_KEY_UNIT_INFO; /** * 客户端:startRpc ——> filter --> beforeSend --> 存入tracer信息 --> clientReceived @@ -114,7 +117,7 @@ public static void beforeSend(SofaRequest sofaRequest, ConsumerConfig consumerCo if (StringUtils.isNotBlank(route)) { Map map = new HashMap<>(); map.put(USERID_KEY, route); - header.put(TripleHeadKeys.HEAD_KEY_UNIT_INFO.name(), JSONUtils.toJSONString(map)); + header.put(HEAD_KEY_UNIT_INFO.name(), JSONUtils.toJSONString(map)); } if (StringUtils.isNotEmpty(consumerConfig.getUniqueId())) { @@ -300,4 +303,22 @@ public static void serverSend(SofaRequest request, final Metadata requestHeaders EventBus.post(new ServerSendEvent(request, response, throwable)); } } + + public static String getUserId(Metadata requestHeaders) { + String unitInfo = requestHeaders.get(HEAD_KEY_UNIT_INFO); + if (unitInfo == null) { + return null; + } + try { + Map unitInfoMap = JSON.parseObject(unitInfo, + new TypeReference>() { + }); + if (unitInfoMap != null) { + return unitInfoMap.get(USERID_KEY); + } + } catch (Exception e) { + LOGGER.warn("Failed to parse tri-unit-info: " + unitInfo, e); + } + return null; + } } \ No newline at end of file diff --git a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java index 1ea78e9b3..47043d2cc 100644 --- a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java +++ b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java @@ -53,4 +53,14 @@ public void testBeforeSend() { Assert.assertEquals("value2", metadata.get(TripleHeadKeys.getKey("triple.header.object.key2"))); } + @Test + public void testGetUserId() { + Metadata metadata = new Metadata(); + Assert.assertNull(TripleTracerAdapter.getUserId(metadata)); + metadata.put(TripleHeadKeys.HEAD_KEY_UNIT_INFO, "test"); + Assert.assertNull(TripleTracerAdapter.getUserId(metadata)); + metadata.put(TripleHeadKeys.HEAD_KEY_UNIT_INFO, "{\"userid\":\"99\"}"); + Assert.assertEquals("99", TripleTracerAdapter.getUserId(metadata)); + } + } \ No newline at end of file From d1375ba0ee6a8f8d4c3a75d478b3074a030f574d Mon Sep 17 00:00:00 2001 From: evenliu Date: Tue, 25 Mar 2025 19:48:17 +0800 Subject: [PATCH 64/64] V5.13.3 release to v5.14.0 (#1486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix triple header and usedId problem * Increase the extensibility of the header conversion context. * fix the triple header context transfer issue * fix the triple header context transfer issue (#1476) * fix triple POJO stream parent interface method not cache stream call type issue (#1481) Co-authored-by: liujianjun.ljj * fix method timeout resolve problem (#1478) Co-authored-by: liujianjun.ljj * fix triple stream deserialize issue when in serverless scene (#1480) Co-authored-by: liujianjun.ljj * fix: hessian deserialize support sofa.serialize.dynamic.load.enable (#1482) (cherry picked from commit d20062fcda96308cbf2f2525f1f60ff6547d6d7f) Co-authored-by: 辰霖 * modify permitKeepAliveTime and permitKeepAliveWithoutCalls to avoid too many ping problem (#1483) Co-authored-by: liujianjun.ljj * Fix serialization and deserialization classloader issues in serverless scene (#1484) Co-authored-by: liujianjun.ljj * enhance triple tracelog in server (#1477) Co-authored-by: liujianjun.ljj * 5.13.3 release --------- Co-authored-by: liujianjun.ljj Co-authored-by: 辰霖 --- .../alipay/sofa/rpc/common/RpcConstants.java | 6 +- .../sofa/rpc/config/ConsumerConfig.java | 7 +- .../sofa/rpc/core/request/SofaRequest.java | 7 +- .../sofa/rpc/config/ConsumerConfigTest.java | 56 +++++ remoting/pom.xml | 5 + remoting/remoting-triple/pom.xml | 4 + .../ClientHeaderClientInterceptor.java | 68 +++++- .../ServerReqHeaderInterceptor.java | 226 +++++++++++------- .../stream/ClientStreamObserverAdapter.java | 56 ++++- .../rpc/server/triple/GenericServiceImpl.java | 29 ++- .../sofa/rpc/server/triple/TripleServer.java | 3 + .../sofatracer/TripleTracerAdapter.java | 53 +++- .../transport/triple/TripleClientInvoker.java | 5 +- .../alipay/sofa/rpc/utils/SofaProtoUtils.java | 2 +- .../sofa/rpc/utils/TripleExceptionUtils.java | 16 ++ .../sofatracer/TripleTracerAdapterTest.java | 2 +- .../rpc/test/triple/stream/HelloService.java | 2 +- .../test/triple/stream/HelloServiceImpl.java | 11 + .../rpc/test/triple/stream/ParentService.java | 31 +++ .../stream/TripleGenericStreamTest.java | 34 +++ 20 files changed, 497 insertions(+), 126 deletions(-) create mode 100644 core/api/src/test/java/com/alipay/sofa/rpc/config/ConsumerConfigTest.java create mode 100644 test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ParentService.java diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java index 8c77e3223..0f25bb8b4 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/common/RpcConstants.java @@ -128,15 +128,15 @@ public class RpcConstants { /** * 调用方式:客户端流 */ - public static final String INVOKER_TYPE_CLIENT_STREAMING = "clientStream"; + public static final String INVOKER_TYPE_CLIENT_STREAMING = "client_stream"; /** * 调用方式:服务端流 */ - public static final String INVOKER_TYPE_SERVER_STREAMING = "serverStream"; + public static final String INVOKER_TYPE_SERVER_STREAMING = "server_stream"; /** * 调用方式:双向流 */ - public static final String INVOKER_TYPE_BI_STREAMING = "bidirectionalStream"; + public static final String INVOKER_TYPE_BI_STREAMING = "bi_stream"; /** * Hessian序列化 [不推荐] diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java b/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java index 031a9316a..2dfa5ef4c 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/config/ConsumerConfig.java @@ -933,8 +933,11 @@ public int getMethodRetries(String methodName) { * @return the time out */ public int getMethodTimeout(String methodName) { - return (Integer) getMethodConfigValue(methodName, RpcConstants.CONFIG_KEY_TIMEOUT, - getTimeout()); + Object methodTimeout = getMethodConfigValue(methodName, RpcConstants.CONFIG_KEY_TIMEOUT); + if (methodTimeout == null || ((Integer) methodTimeout) == 0) { + return getTimeout(); + } + return (Integer) methodTimeout; } /** diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/core/request/SofaRequest.java b/core/api/src/main/java/com/alipay/sofa/rpc/core/request/SofaRequest.java index 1829ec7a4..aec722318 100644 --- a/core/api/src/main/java/com/alipay/sofa/rpc/core/request/SofaRequest.java +++ b/core/api/src/main/java/com/alipay/sofa/rpc/core/request/SofaRequest.java @@ -306,7 +306,10 @@ public SofaRequest setData(AbstractByteBuf data) { * @return 如果是Future和Callback,是异步请求 */ public boolean isAsync() { - return invokeType != null && (RpcConstants.INVOKER_TYPE_CALLBACK.equals(invokeType) - || RpcConstants.INVOKER_TYPE_FUTURE.equals(invokeType)); + return RpcConstants.INVOKER_TYPE_CALLBACK.equals(invokeType) + || RpcConstants.INVOKER_TYPE_FUTURE.equals(invokeType) + || RpcConstants.INVOKER_TYPE_BI_STREAMING.equals(invokeType) + || RpcConstants.INVOKER_TYPE_SERVER_STREAMING.equals(invokeType) + || RpcConstants.INVOKER_TYPE_CLIENT_STREAMING.equals(invokeType); } } \ No newline at end of file diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/config/ConsumerConfigTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/config/ConsumerConfigTest.java new file mode 100644 index 000000000..78eef2adb --- /dev/null +++ b/core/api/src/test/java/com/alipay/sofa/rpc/config/ConsumerConfigTest.java @@ -0,0 +1,56 @@ +/* + * 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 com.alipay.sofa.rpc.config; + +import com.alipay.sofa.rpc.invoke.Invoker; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Even + * @date 2025/3/4 21:36 + */ +public class ConsumerConfigTest { + + @Test + public void testMethodTimeout() { + ConsumerConfig consumerConfig = new ConsumerConfig<>(); + consumerConfig.setTimeout(4000); + consumerConfig.setInterfaceId(Invoker.class.getName()); + consumerConfig.getConfigValueCache(true); + Assert.assertEquals(4000, consumerConfig.getMethodTimeout("invoke")); + + List methodConfigs = new ArrayList<>(); + MethodConfig methodConfig = new MethodConfig(); + methodConfig.setName("invoke"); + methodConfigs.add(methodConfig); + consumerConfig.setMethods(methodConfigs); + consumerConfig.getConfigValueCache(true); + Assert.assertEquals(4000, consumerConfig.getMethodTimeout("invoke")); + + methodConfig.setTimeout(5000); + consumerConfig.getConfigValueCache(true); + Assert.assertEquals(5000, consumerConfig.getMethodTimeout("invoke")); + + methodConfig.setTimeout(-1); + consumerConfig.getConfigValueCache(true); + Assert.assertEquals(-1, consumerConfig.getMethodTimeout("invoke")); + } +} \ No newline at end of file diff --git a/remoting/pom.xml b/remoting/pom.xml index e194aff60..1fea28bf6 100644 --- a/remoting/pom.xml +++ b/remoting/pom.xml @@ -88,6 +88,11 @@ sofa-rpc-log-common-tools ${project.parent.version} + + com.alipay.sofa + sofa-rpc-tracer-opentracing + ${project.parent.version} + diff --git a/remoting/remoting-triple/pom.xml b/remoting/remoting-triple/pom.xml index 6c9458d33..9c8dc44b7 100644 --- a/remoting/remoting-triple/pom.xml +++ b/remoting/remoting-triple/pom.xml @@ -66,5 +66,9 @@ com.alipay.sofa tracer-core + + com.alipay.sofa + sofa-rpc-tracer-opentracing + diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ClientHeaderClientInterceptor.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ClientHeaderClientInterceptor.java index c7d27c801..ca63b66ba 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ClientHeaderClientInterceptor.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ClientHeaderClientInterceptor.java @@ -16,12 +16,20 @@ */ package com.alipay.sofa.rpc.interceptor; +import com.alipay.common.tracer.core.context.trace.SofaTraceContext; +import com.alipay.common.tracer.core.holder.SofaTraceContextHolder; +import com.alipay.common.tracer.core.span.SofaTracerSpan; import com.alipay.sofa.rpc.config.ConsumerConfig; +import com.alipay.sofa.rpc.context.RpcInternalContext; import com.alipay.sofa.rpc.context.RpcInvokeContext; import com.alipay.sofa.rpc.context.RpcRunningState; import com.alipay.sofa.rpc.core.request.SofaRequest; +import com.alipay.sofa.rpc.core.response.SofaResponse; +import com.alipay.sofa.rpc.event.ClientAsyncReceiveEvent; +import com.alipay.sofa.rpc.event.EventBus; import com.alipay.sofa.rpc.server.triple.TripleContants; import com.alipay.sofa.rpc.tracer.sofatracer.TripleTracerAdapter; +import com.alipay.sofa.rpc.utils.TripleExceptionUtils; import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.ClientCall; @@ -59,12 +67,15 @@ public ClientCall interceptCall(MethodDescriptor responseListener, Metadata requestHeader) { - + RpcInternalContext internalContext = RpcInternalContext.getContext(); RpcInvokeContext context = RpcInvokeContext.getContext(); SofaRequest sofaRequest = (SofaRequest) context.get(TripleContants.SOFA_REQUEST_KEY); - ConsumerConfig consumerConfig = (ConsumerConfig) context.get(TripleContants.SOFA_CONSUMER_CONFIG_KEY); - TripleTracerAdapter.beforeSend(sofaRequest, consumerConfig, requestHeader); + ConsumerConfig consumerConfig = (ConsumerConfig) context + .get(TripleContants.SOFA_CONSUMER_CONFIG_KEY); + TripleTracerAdapter.beforeSend(sofaRequest, consumerConfig, requestHeader, method); + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + SofaTracerSpan clientSpan = sofaTraceContext.getCurrentSpan(); if (RpcRunningState.isDebugMode()) { LOGGER.info("[2]prepare to send from client:{}", requestHeader); } @@ -80,18 +91,48 @@ public void onHeaders(Metadata responseHeader) { @Override public void onMessage(RespT message) { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[4]response message received from server:{}", message); + // onMessage -> onNext() + try { + if (sofaRequest.isAsync()) { + RpcInvokeContext.setContext(context); + sofaTraceContext.push(clientSpan); + } + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[4]response message received from server:{}", message); + } + super.onMessage(message); + } finally { + if (sofaRequest.isAsync()) { + sofaTraceContext.clear(); + RpcInvokeContext.removeContext(); + } } - super.onMessage(message); } @Override public void onClose(Status status, Metadata trailers) { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[5]response close received from server:{},trailers:{}", status, trailers); + // onClose -> onComplete() or onError() + try { + if (sofaRequest.isAsync()) { + RpcInvokeContext.setContext(context); + sofaTraceContext.push(clientSpan); + } + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[5]response close received from server:{},trailers:{}", status, trailers); + } + super.onClose(status, trailers); + } finally { + if (sofaRequest.isAsync()) { + Throwable throwable = TripleExceptionUtils.getThrowableFromStatus(status); + RpcInternalContext.setContext(internalContext); + if (EventBus.isEnable(ClientAsyncReceiveEvent.class)) { + EventBus.post(new ClientAsyncReceiveEvent(consumerConfig, null, + sofaRequest, new SofaResponse(), throwable)); + } + RpcInvokeContext.removeContext(); + RpcInternalContext.removeAllContext(); + } } - super.onClose(status, trailers); } @Override @@ -104,6 +145,15 @@ public void onReady() { }, requestHeader); } + @Override + public void sendMessage(ReqT message) { + try { + super.sendMessage(message); + } catch (Throwable t) { + LOGGER.error("Client invoke grpc sendMessage meet error:", t); + throw t; + } + } }; } } \ No newline at end of file diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java index 20c57990c..e80444d16 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/interceptor/ServerReqHeaderInterceptor.java @@ -21,7 +21,6 @@ import com.alipay.common.tracer.core.span.SofaTracerSpan; import com.alipay.sofa.rpc.context.RpcInvokeContext; import com.alipay.sofa.rpc.context.RpcRunningState; -import com.alipay.sofa.rpc.context.RpcRuntimeContext; import com.alipay.sofa.rpc.core.request.SofaRequest; import com.alipay.sofa.rpc.core.response.SofaResponse; import com.alipay.sofa.rpc.tracer.sofatracer.TracingContextKey; @@ -57,109 +56,164 @@ public ServerReqHeaderInterceptor(ServerServiceDefinition serverServiceDefinitio public ServerCall.Listener interceptCall(final ServerCall call, final Metadata requestHeaders, ServerCallHandler next) { - final ServerServiceDefinition serverServiceDefinition = this.getServerServiceDefinition(); + try { + final ServerServiceDefinition serverServiceDefinition = this.getServerServiceDefinition(); - SofaResponse sofaResponse = new SofaResponse(); - final Throwable[] throwable = { null }; - SofaRequest sofaRequest = new SofaRequest(); + SofaResponse sofaResponse = new SofaResponse(); + SofaRequest sofaRequest = new SofaRequest(); - Context ctxWithSpan = convertHeaderToContext(call, requestHeaders, sofaRequest, serverServiceDefinition); + Context ctxWithSpan = convertHeaderToContext(call, requestHeaders, sofaRequest, serverServiceDefinition); - //这里和下面不在一个线程 - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[1]header received from client:" + requestHeaders); - } - - ServerCall realCall = new ForwardingServerCall.SimpleForwardingServerCall(call) { - @Override - public void sendHeaders(Metadata responseHeaders) { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[4]send response header:{}", responseHeaders); - } - super.sendHeaders(responseHeaders); + //这里和下面不在一个线程 + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[1]header received from client:{}", requestHeaders); } - //服务端发完了 - @Override - public void sendMessage(RespT message) { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[5]send response message:{}", message); + ServerCall realCall = new ForwardingServerCall.SimpleForwardingServerCall(call) { + @Override + public void sendHeaders(Metadata responseHeaders) { + try { + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[4]send response header:{}", responseHeaders); + } + super.sendHeaders(responseHeaders); + } catch (Throwable t) { + LOGGER.error("Server invoke grpc sendHeaders meet error:", t); + throw t; + } } - super.sendMessage(message); - sofaResponse.setAppResponse(message); - } - - @Override - public void close(Status status, Metadata trailers) { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[6]send response message:{},trailers:{}", status, trailers); + //服务端发完了 + @Override + public void sendMessage(RespT message) { + try { + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[5]send response message:{}", message); + } + super.sendMessage(message); + + sofaResponse.setAppResponse(message); + } catch (Throwable t) { + LOGGER.error("Server invoke grpc sendMessage meet error:", t); + throw t; + } } - super.close(status, trailers); - } - }; - - ServerCall.Listener listenerWithContext = - Contexts.interceptCall(ctxWithSpan, realCall, requestHeaders, next); - ForwardingServerCallListener.SimpleForwardingServerCallListener result = new ForwardingServerCallListener.SimpleForwardingServerCallListener( - listenerWithContext) { + @Override + public void close(Status status, Metadata trailers) { + // onError -> close + try { + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[6]send response message:{},trailers:{}", status, trailers); + } + if (status.getCause() != null) { + status = status.withDescription(status.getCause().getMessage()); + } + super.close(status, trailers); + } finally { + if (!status.isOk()) { + Throwable cause = status.getCause(); + TripleTracerAdapter.serverSend(sofaRequest, requestHeaders, sofaResponse, cause, + ctxWithSpan); + } + } - //完成的时候走到这里 - @Override - public void onComplete() { - // 和代码执行不一定在一个线程池 - super.onComplete(); - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[7]server processed done received from client:" + requestHeaders); } - TripleTracerAdapter.serverReceived(sofaRequest, serverServiceDefinition, call, requestHeaders); - - //进行一下补偿 - SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); - SofaTracerSpan serverSpan = sofaTraceContext.getCurrentSpan(); - SofaTracerSpan originalSpan = (SofaTracerSpan) TracingContextKey.getKey().get(ctxWithSpan); - serverSpan.setStartTime(originalSpan.getStartTime()); - serverSpan.setTag("remote.ip", originalSpan.getTagsWithStr().get("remote.ip")); - long endTime = RpcRuntimeContext.now(); - serverSpan.setTag("biz.impl.time", endTime - originalSpan.getStartTime()); - TripleTracerAdapter.serverSend(sofaRequest, requestHeaders, sofaResponse, throwable[0]); + }; + ServerCall.Listener listenerWithContext; + try { + listenerWithContext = Contexts.interceptCall(ctxWithSpan, realCall, requestHeaders, next); + } catch (Throwable t) { + LOGGER.error("Server invoke grpc interceptCall meet error:", t); + TripleTracerAdapter.serverSend(sofaRequest, requestHeaders, sofaResponse, t, ctxWithSpan); + Status status = Status.UNKNOWN.withDescription(t.getMessage()).withCause(t); + throw new StatusRuntimeException(status); } + RpcInvokeContext invokeContext = RpcInvokeContext.getContext(); + return new ForwardingServerCallListener.SimpleForwardingServerCallListener( + listenerWithContext) { + + @Override + public void onCancel() { + // onCancel -> onError() + try { + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + SofaTracerSpan originalSpan = (SofaTracerSpan) TracingContextKey.getKey().get(ctxWithSpan); + sofaTraceContext.push(originalSpan); + RpcInvokeContext.setContext(invokeContext); + super.onCancel(); + } finally { + TripleTracerAdapter.serverSend(sofaRequest, requestHeaders, sofaResponse, + new StatusRuntimeException(Status.CANCELLED, new Metadata()), ctxWithSpan); + } + } - //客户端发完了 - @Override - public void onHalfClose() { - try { - doOnHalfClose(); - } finally { - RpcInvokeContext.removeContext(); + //完成的时候走到这里 + @Override + public void onComplete() { + try { + // 和代码执行不一定在一个线程池 + super.onComplete(); + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[7]server processed done received from client:" + requestHeaders); + } + } finally { + TripleTracerAdapter.serverSend(sofaRequest, requestHeaders, sofaResponse, null, ctxWithSpan); + } } - } - private void doOnHalfClose() { - if (RpcRunningState.isDebugMode()) { - LOGGER.info("[2]body received done from client:" + requestHeaders); + @Override + public void onMessage(ReqT message) { + // onMessage -> onNext() + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + try { + SofaTracerSpan originalSpan = (SofaTracerSpan) TracingContextKey.getKey().get(ctxWithSpan); + sofaTraceContext.push(originalSpan); + RpcInvokeContext.setContext(invokeContext); + super.onMessage(message); + } catch (Throwable t) { + LOGGER.error("Server invoke grpc onMessage meet error:", t); + throw t; + } finally { + RpcInvokeContext.removeContext(); + sofaTraceContext.clear(); + } } - // 服务端收到所有信息 - TripleTracerAdapter.serverReceived(sofaRequest, serverServiceDefinition, call, requestHeaders); - try { - super.onHalfClose(); - } catch (Throwable t) { - // 统一处理异常 - StatusRuntimeException exception = fromThrowable(t); - // 调用 call.close() 发送 Status 和 metadata - // 这个方式和 onError()本质是一样的 - call.close(exception.getStatus(), exception.getTrailers()); - throwable[0] = t; + + //客户端发完了 + @Override + public void onHalfClose() { + // onHalfClose -> onComplete() -> close + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + try { + SofaTracerSpan originalSpan = (SofaTracerSpan) TracingContextKey.getKey().get(ctxWithSpan); + sofaTraceContext.push(originalSpan); + RpcInvokeContext.setContext(invokeContext); + doOnHalfClose(); + } finally { + RpcInvokeContext.removeContext(); + sofaTraceContext.clear(); + } } - } - private StatusRuntimeException fromThrowable(Throwable t) { - final Metadata trailers = new Metadata(); - return new StatusRuntimeException(Status.UNKNOWN, trailers); - } - }; - return result; + private void doOnHalfClose() { + if (RpcRunningState.isDebugMode()) { + LOGGER.info("[2]body received done from client:" + requestHeaders); + } + try { + super.onHalfClose(); + } catch (Throwable t) { + // 统一处理异常 + final Metadata trailers = new Metadata(); + Status status = Status.UNKNOWN.withDescription(t.getMessage()).withCause(t); + realCall.close(status, trailers); + } + } + }; + } finally { + RpcInvokeContext.removeContext(); + SofaTraceContextHolder.getSofaTraceContext().clear(); + } } protected Context convertHeaderToContext(ServerCall call, diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java index 72fbf75ff..ff72fa773 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/message/triple/stream/ClientStreamObserverAdapter.java @@ -23,49 +23,81 @@ import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf; import com.alipay.sofa.rpc.transport.SofaStreamObserver; import io.grpc.stub.StreamObserver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * ClientStreamObserverAdapter. */ public class ClientStreamObserverAdapter implements StreamObserver { + public static final Logger LOGGER = LoggerFactory.getLogger(ClientStreamObserverAdapter.class); + private final SofaStreamObserver sofaStreamObserver; private final Serializer serializer; private volatile Class returnType; - public ClientStreamObserverAdapter(SofaStreamObserver sofaStreamObserver, byte serializeType) { + private final ClassLoader classLoader; + + /** + * Instantiates a new triple stream invoker callback adapter. + * + * @param sofaStreamObserver stream callback + * @param serializeType serialize type + * @param classLoader Classloader of the rpc calling thread + */ + public ClientStreamObserverAdapter(SofaStreamObserver sofaStreamObserver, byte serializeType, + ClassLoader classLoader) { this.sofaStreamObserver = sofaStreamObserver; this.serializer = SerializerFactory.getSerializer(serializeType); + this.classLoader = classLoader; } @Override public void onNext(triple.Response response) { byte[] responseData = response.getData().toByteArray(); - Object appResponse = null; + Object appResponse; String returnTypeName = response.getType(); if (responseData != null && responseData.length > 0) { - if (returnType == null && !returnTypeName.isEmpty()) { - try { - returnType = Class.forName(returnTypeName); - } catch (ClassNotFoundException e) { - throw new SofaRpcException(RpcErrorType.CLIENT_SERIALIZE, "Can not find return type :" + returnType); + ClassLoader oldClassloader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + if (returnType == null && !returnTypeName.isEmpty()) { + returnType = Class.forName(returnTypeName, true, classLoader); } + appResponse = serializer.decode(new ByteArrayWrapperByteBuf(responseData), returnType, null); + sofaStreamObserver.onNext(appResponse); + } catch (ClassNotFoundException e) { + LOGGER.error("Can not find return type :" + returnType, e); + throw new SofaRpcException(RpcErrorType.CLIENT_DESERIALIZE, "Can not find return type :" + returnType, + e); + } finally { + Thread.currentThread().setContextClassLoader(oldClassloader); } - appResponse = serializer.decode(new ByteArrayWrapperByteBuf(responseData), returnType, null); } - - sofaStreamObserver.onNext(appResponse); } @Override public void onError(Throwable t) { - sofaStreamObserver.onError(t); + ClassLoader oldClassloader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + sofaStreamObserver.onError(t); + } finally { + Thread.currentThread().setContextClassLoader(oldClassloader); + } } @Override public void onCompleted() { - sofaStreamObserver.onCompleted(); + ClassLoader oldClassloader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(classLoader); + sofaStreamObserver.onCompleted(); + } finally { + Thread.currentThread().setContextClassLoader(oldClassloader); + } } } diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java index 4b96e7cfb..06c2469ac 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/GenericServiceImpl.java @@ -131,20 +131,37 @@ public StreamObserver genericBiStream(StreamObserver response @Override public void onNext(Request request) { - checkInitialize(request); - Object message = getInvokeArgs(request, argTypes, serializer, false)[0]; - serverResponseHandler.setSerializeType(serializeType); - clientHandler.onNext(message); + try { + Thread.currentThread().setContextClassLoader(serviceClassLoader); + checkInitialize(request); + Object message = getInvokeArgs(request, argTypes, serializer, false)[0]; + serverResponseHandler.setSerializeType(serializeType); + clientHandler.onNext(message); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } } @Override public void onError(Throwable t) { - clientHandler.onError(t); + try { + Thread.currentThread().setContextClassLoader(serviceClassLoader); + clientHandler.onError(t); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } @Override public void onCompleted() { - clientHandler.onCompleted(); + try { + Thread.currentThread().setContextClassLoader(serviceClassLoader); + clientHandler.onCompleted(); + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } + } private void checkInitialize(Request request) { diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java index 47f225352..7494dfb1c 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/server/triple/TripleServer.java @@ -65,6 +65,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -142,6 +143,8 @@ public void init(ServerConfig serverConfig) { .executor(bizThreadPool) .channelType(constructChannel()) .maxInboundMessageSize(RpcConfigs.getIntValue(RpcOptions.TRANSPORT_GRPC_MAX_INBOUND_MESSAGE_SIZE)) + .permitKeepAliveTime(1, TimeUnit.SECONDS) + .permitKeepAliveWithoutCalls(true) .build(); this.lock = new ReentrantLock(); } diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java index 50800b934..041a57c72 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapter.java @@ -41,8 +41,11 @@ import com.alipay.sofa.rpc.log.LoggerFactory; import com.alipay.sofa.rpc.server.triple.TripleContants; import com.alipay.sofa.rpc.server.triple.TripleHeadKeys; +import com.alipay.sofa.rpc.tracer.sofatracer.log.tags.RpcSpanTags; +import io.grpc.Context; import io.grpc.Grpc; import io.grpc.Metadata; +import io.grpc.MethodDescriptor; import io.grpc.ServerCall; import io.grpc.ServerServiceDefinition; @@ -76,7 +79,20 @@ public class TripleTracerAdapter { * @param sofaRequest SofaRequest * @param requestHeader Metadata */ - public static void beforeSend(SofaRequest sofaRequest, ConsumerConfig consumerConfig, Metadata requestHeader) { + @Deprecated + public static void beforeSend(SofaRequest sofaRequest, ConsumerConfig consumerConfig, Metadata requestHeader) { + beforeSend(sofaRequest, consumerConfig, requestHeader, null); + } + + /** + * 存入tracer信息 + * + * @param sofaRequest + * @param consumerConfig + * @param requestHeader + * @param method + */ + public static void beforeSend(SofaRequest sofaRequest, ConsumerConfig consumerConfig, Metadata requestHeader, MethodDescriptor method) { // 客户端设置请求服务端的Header // tracer信息放入request 发到服务端 @@ -108,6 +124,25 @@ public static void beforeSend(SofaRequest sofaRequest, ConsumerConfig consumerCo header.put(TripleHeadKeys.HEAD_KEY_SYS_BAGGAGE_TYPE.name(), sofaTracerSpanContext.getSysSerializedBaggage()); + if (method != null) { + switch (method.getType()) { + case CLIENT_STREAMING : + sofaRequest.setInvokeType(RpcConstants.INVOKER_TYPE_CLIENT_STREAMING); + clientSpan.setTag(RpcSpanTags.INVOKE_TYPE, RpcConstants.INVOKER_TYPE_CLIENT_STREAMING); + break; + case SERVER_STREAMING : + sofaRequest.setInvokeType(RpcConstants.INVOKER_TYPE_SERVER_STREAMING); + clientSpan.setTag(RpcSpanTags.INVOKE_TYPE, RpcConstants.INVOKER_TYPE_SERVER_STREAMING); + break; + case BIDI_STREAMING: + sofaRequest.setInvokeType(RpcConstants.INVOKER_TYPE_BI_STREAMING); + clientSpan.setTag(RpcSpanTags.INVOKE_TYPE, RpcConstants.INVOKER_TYPE_BI_STREAMING); + break; + default: + header.put(TripleHeadKeys.HEAD_KEY_INVOKE_TYPE.name(), RpcConstants.INVOKER_TYPE_SYNC); + } + sofaRequest.addRequestProp(RemotingConstants.HEAD_INVOKE_TYPE, sofaRequest.getInvokeType()); + } } //获取 RPC 上下文 @@ -288,9 +323,25 @@ public static void serverReceived(SofaRequest sofaRequest, ServerServiceDefiniti /** * 适配服务端serverSend */ + @Deprecated public static void serverSend(SofaRequest request, final Metadata requestHeaders, SofaResponse response, Throwable throwable) { + serverSend(request, requestHeaders, response, throwable, null); + } + + /** + * 适配服务端serverSend + */ + public static void serverSend(SofaRequest request, final Metadata requestHeaders, SofaResponse response, + Throwable throwable, Context ctxWithSpan) { if (EventBus.isEnable(ServerSendEvent.class)) { + if (ctxWithSpan != null) { + SofaTraceContext sofaTraceContext = SofaTraceContextHolder.getSofaTraceContext(); + if (sofaTraceContext.getCurrentSpan() == null) { + SofaTracerSpan originalSpan = (SofaTracerSpan) TracingContextKey.getKey().get(ctxWithSpan); + sofaTraceContext.push(originalSpan); + } + } if (request == null) { request = new SofaRequest(); } diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java index af681155c..1704fdb61 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/transport/triple/TripleClientInvoker.java @@ -193,7 +193,8 @@ private SofaResponse genericBinaryStreamCall(SofaRequest sofaRequest, int timeou call, new ClientStreamObserverAdapter( sofaStreamObserver, - sofaRequest.getSerializeType() + sofaRequest.getSerializeType(), + ClassLoaderUtils.getCurrentClassLoader() ) ); SofaStreamObserver handler = new SofaStreamObserver() { @@ -231,7 +232,7 @@ private SofaResponse genericServerStreamCall(SofaRequest sofaRequest, int timeou Request req = SofaProtoUtils.buildRequest(sofaRequest.getMethodArgSigs(), sofaRequest.getMethodArgs(), serialization, serializer, 1); - ClientStreamObserverAdapter responseObserver = new ClientStreamObserverAdapter(sofaStreamObserver, sofaRequest.getSerializeType()); + ClientStreamObserverAdapter responseObserver = new ClientStreamObserverAdapter(sofaStreamObserver, sofaRequest.getSerializeType(), ClassLoaderUtils.getCurrentClassLoader()); ClientCalls.asyncServerStreamingCall(call, req, responseObserver); diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java index 780d7f5a8..9faa90077 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/SofaProtoUtils.java @@ -96,7 +96,7 @@ public static MethodDescriptor.MethodType mapGrpcCallType(String callType) { public static Map cacheStreamCallType(Class proxyClass) { Map methodCallType = new ConcurrentHashMap<>(); - Method[] declaredMethods = proxyClass.getDeclaredMethods(); + Method[] declaredMethods = proxyClass.getMethods(); for (Method method : declaredMethods) { String streamType = mapStreamType(method); if (StringUtils.isNotBlank(streamType)) { diff --git a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java index 5387e3af3..e7b56c983 100644 --- a/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java +++ b/remoting/remoting-triple/src/main/java/com/alipay/sofa/rpc/utils/TripleExceptionUtils.java @@ -16,6 +16,10 @@ */ package com.alipay.sofa.rpc.utils; +import com.alipay.sofa.rpc.core.exception.RpcErrorType; +import com.alipay.sofa.rpc.core.exception.SofaRouteException; +import com.alipay.sofa.rpc.core.exception.SofaRpcException; +import com.alipay.sofa.rpc.core.exception.SofaTimeOutException; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -29,4 +33,16 @@ public static StatusRuntimeException asStatusRuntimeException(Throwable t) { } } + public static Throwable getThrowableFromStatus(Status status) { + if (status.getCode() == Status.OK.getCode()) { + return null; + } else if (status.getCode() == Status.UNAVAILABLE.getCode()) { + return new SofaRouteException(status.getDescription(), status.getCause()); + } else if (status.getCode() == Status.DEADLINE_EXCEEDED.getCode()) { + return new SofaTimeOutException(status.getDescription(), status.getCause()); + } else { + return new SofaRpcException(RpcErrorType.UNKNOWN, status.getDescription(), status.getCause()); + } + } + } diff --git a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java index 47043d2cc..bf9288ab9 100644 --- a/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java +++ b/remoting/remoting-triple/src/test/java/com/alipay/sofa/rpc/tracer/sofatracer/TripleTracerAdapterTest.java @@ -46,7 +46,7 @@ public void testBeforeSend() { sofaRequest.addRequestProp(HEAD_TARGET_SERVICE, "targetService2"); ConsumerConfig consumerConfig = new ConsumerConfig(); Metadata metadata = new Metadata(); - TripleTracerAdapter.beforeSend(sofaRequest, consumerConfig, metadata); + TripleTracerAdapter.beforeSend(sofaRequest, consumerConfig, metadata, null); Assert.assertEquals("targetService2", metadata.get(TripleHeadKeys.getKey(HEAD_TARGET_SERVICE))); Assert.assertEquals("triple.header.value", metadata.get(TripleHeadKeys.getKey("triple.header.key"))); Assert.assertEquals("value1", metadata.get(TripleHeadKeys.getKey("triple.header.object.key1"))); diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java index b66d34a46..f79aa4610 100644 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloService.java @@ -18,7 +18,7 @@ import com.alipay.sofa.rpc.transport.SofaStreamObserver; -public interface HelloService { +public interface HelloService extends ParentService { String CMD_TRIGGER_STREAM_FINISH = "finish"; diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java index 3d40fc350..66c960cfc 100644 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/HelloServiceImpl.java @@ -78,4 +78,15 @@ public void sayHelloServerStream(ClientRequest clientRequest, SofaStreamObserver } } + @Override + public ServerResponse sayHello(ClientRequest clientRequest) { + return new ServerResponse(clientRequest.getMsg(), clientRequest.getCount()); + } + + @Override + public void parentSayHelloServerStream(ClientRequest clientRequest, + SofaStreamObserver sofaStreamObserver) { + sayHelloServerStream(clientRequest, sofaStreamObserver); + } + } diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ParentService.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ParentService.java new file mode 100644 index 000000000..62f1dccb1 --- /dev/null +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/ParentService.java @@ -0,0 +1,31 @@ +/* + * 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 com.alipay.sofa.rpc.test.triple.stream; + +import com.alipay.sofa.rpc.transport.SofaStreamObserver; + +/** + * @author Even + * @date 2025/3/4 23:49 + */ +public interface ParentService { + + ServerResponse sayHello(ClientRequest clientRequest); + + void parentSayHelloServerStream(ClientRequest clientRequest, SofaStreamObserver sofaStreamObserver); + +} diff --git a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java index bf145e502..7acc32303 100644 --- a/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java +++ b/test/test-integration/src/test/java/com/alipay/sofa/rpc/test/triple/stream/TripleGenericStreamTest.java @@ -73,6 +73,7 @@ public static void beforeClass() throws InterruptedException { .setProtocol("tri") .setDirectUrl("triple://127.0.0.1:50066"); helloServiceRef = consumerConfig.refer(); + Thread.sleep(5000); } @AfterClass @@ -84,6 +85,39 @@ public static void afterClass() { RpcInvokeContext.removeContext(); } + @Test + public void testTripleParentCall() throws InterruptedException { + ClientRequest clientRequest = new ClientRequest("hello world", 5); + ServerResponse serverResponse = helloServiceRef.sayHello(clientRequest); + Assert.assertEquals("hello world", serverResponse.getMsg()); + + CountDownLatch countDownLatch = new CountDownLatch(6); + AtomicBoolean receivedFinish = new AtomicBoolean(false); + List list = new ArrayList<>(); + helloServiceRef.parentSayHelloServerStream(clientRequest, new SofaStreamObserver() { + @Override + public void onNext(ServerResponse message) { + list.add(message); + countDownLatch.countDown(); + } + + @Override + public void onCompleted() { + receivedFinish.set(true); + countDownLatch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + countDownLatch.countDown(); + } + }); + + Assert.assertTrue(countDownLatch.await(20, TimeUnit.SECONDS)); + Assert.assertEquals(5, list.size()); + Assert.assertTrue(receivedFinish.get()); + } + @Test public void testTripleBiStreamFinish() throws InterruptedException { testTripleBiStream(false);