You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/09/28 02:59:07 UTC
[dubbo] branch 3.0 updated: Refactor Injvm invoke (#8926)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new 31c5ee4 Refactor Injvm invoke (#8926)
31c5ee4 is described below
commit 31c5ee4086d7714850124f4b79f292c3443e5784
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Tue Sep 28 10:58:51 2021 +0800
Refactor Injvm invoke (#8926)
* Refactor Injvm invoke
* Add ut
* Fix import
* Remove deprecated method & fix ut
* Fix Cluster join
---
.../java/org/apache/dubbo/rpc/cluster/Cluster.java | 2 +-
.../rpc/cluster/directory/UrlStaticDirectory.java | 114 ---------
.../rpc/cluster/support/AvailableCluster.java | 2 +-
.../cluster/support/wrapper/AbstractCluster.java | 8 +-
.../support/wrapper/MockClusterWrapper.java | 4 +-
.../support/wrapper/AbstractClusterTest.java | 7 +-
.../com/alibaba/dubbo/rpc/cluster/Cluster.java | 2 +-
.../org/apache/dubbo/config/ReferenceConfig.java | 17 +-
.../apache/dubbo/config/ReferenceConfigTest.java | 35 +--
.../org/apache/dubbo/config/mock/MockCluster.java | 2 +-
dubbo-distribution/dubbo-all/pom.xml | 6 +
.../apache/dubbo/rpc/cluster/Cluster$Adaptive.java | 5 +-
.../registry/integration/RegistryDirectory.java | 2 +-
.../registry/integration/RegistryProtocol.java | 2 +-
.../rpc/protocol/dubbo/DubboProtocolTest.java | 3 +-
dubbo-rpc/dubbo-rpc-injvm/pom.xml | 8 +-
.../protocol/injvm/DefaultParamDeepCopyUtil.java | 65 ++++++
.../dubbo/rpc/protocol/injvm/InjvmInvoker.java | 107 ++++++++-
.../dubbo/rpc/protocol/injvm/InjvmProtocol.java | 14 +-
.../rpc/protocol/injvm/ParamDeepCopyUtil.java | 20 +-
...ache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil | 1 +
.../test/java/demo/MultiClassLoaderService.java | 15 +-
.../java/demo/MultiClassLoaderServiceImpl.java | 32 +--
.../java/demo/MultiClassLoaderServiceRequest.java | 15 +-
.../java/demo/MultiClassLoaderServiceResult.java | 15 +-
.../rpc/protocol/injvm/InjvmClassLoaderTest.java | 254 +++++++++++++++++++++
.../rpc/protocol/injvm/InjvmDeepCopyTest.java | 111 +++++++++
.../rpc/protocol/injvm/InjvmProtocolTest.java | 15 +-
.../dubbo/rpc/protocol/injvm/ProtocolTest.java | 3 +-
.../dubbo/AbstractHessian2FactoryInitializer.java | 13 ++
30 files changed, 655 insertions(+), 244 deletions(-)
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
index d6d4d5e..909693c 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
@@ -45,7 +45,7 @@ public interface Cluster {
* @throws RpcException
*/
@Adaptive
- <T> Invoker<T> join(Directory<T> directory) throws RpcException;
+ <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException;
static Cluster getCluster(ScopeModel scopeModel, String name) {
return getCluster(scopeModel, name, true);
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/UrlStaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/UrlStaticDirectory.java
deleted file mode 100644
index 37bf1eb..0000000
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/UrlStaticDirectory.java
+++ /dev/null
@@ -1,114 +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 org.apache.dubbo.rpc.cluster.directory;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.RouterChain;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * copy StaticDirectory for rpc protocol url direct
- */
-public class UrlStaticDirectory<T> extends AbstractDirectory<T> {
- private static final Logger logger = LoggerFactory.getLogger(UrlStaticDirectory.class);
-
- private final List<Invoker<T>> invokers;
-
- public UrlStaticDirectory(List<Invoker<T>> invokers) {
- this(null, invokers, null);
- }
-
- public UrlStaticDirectory(List<Invoker<T>> invokers, RouterChain<T> routerChain) {
- this(null, invokers, routerChain);
- }
-
- public UrlStaticDirectory(URL url, List<Invoker<T>> invokers) {
- this(url, invokers, null);
- }
-
- public UrlStaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
- super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
- if (CollectionUtils.isEmpty(invokers)) {
- throw new IllegalArgumentException("invokers == null");
- }
- this.invokers = invokers;
- }
-
- @Override
- public Class<T> getInterface() {
- return invokers.get(0).getInterface();
- }
-
- @Override
- public List<Invoker<T>> getAllInvokers() {
- return invokers;
- }
-
- @Override
- public boolean isAvailable() {
- if (isDestroyed()) {
- return false;
- }
- for (Invoker<T> invoker : invokers) {
- if (invoker.isAvailable()) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void destroy() {
- if (isDestroyed()) {
- return;
- }
- super.destroy();
- for (Invoker<T> invoker : invokers) {
- invoker.destroy();
- }
- invokers.clear();
- }
-
- public void buildRouterChain() {
- RouterChain<T> routerChain = RouterChain.buildChain(getUrl());
- routerChain.setInvokers(invokers);
- routerChain.loop(true);
- this.setRouterChain(routerChain);
- }
-
- @Override
- protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
- List<Invoker<T>> finalInvokers = invokers;
- if (routerChain != null) {
- try {
- finalInvokers = routerChain.route(getConsumerUrl(), invocation);
- } catch (Throwable t) {
- logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
- }
- }
- return finalInvokers == null ? Collections.emptyList() : finalInvokers;
- }
-
-}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
index 6fcc03c..d6c0163 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
@@ -30,7 +30,7 @@ public class AvailableCluster implements Cluster {
public static final String NAME = "available";
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
return new AvailableClusterInvoker<>(directory);
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
index 923ca4e..968ef3e 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java
@@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
-import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
import org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder;
import org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor;
@@ -54,11 +53,12 @@ public abstract class AbstractCluster implements Cluster {
}
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- if (directory instanceof StaticDirectory) {
+ public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
+ if (buildFilterChain) {
+ return buildClusterInterceptors(doJoin(directory));
+ } else {
return doJoin(directory);
}
- return buildClusterInterceptors(doJoin(directory));
}
private <T> AbstractClusterInvoker<T> buildInterceptorInvoker(AbstractClusterInvoker<T> invoker) {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
index 686474f..4f8be0a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
@@ -34,9 +34,9 @@ public class MockClusterWrapper implements Cluster {
}
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
return new MockClusterInvoker<T>(directory,
- this.cluster.join(directory));
+ this.cluster.join(directory, buildFilterChain));
}
public Cluster getCluster() {
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractClusterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractClusterTest.java
index e98d2ba..9eccf0a 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractClusterTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractClusterTest.java
@@ -28,6 +28,7 @@ import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.cluster.filter.DemoService;
import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -65,7 +66,7 @@ public class AbstractClusterTest {
when(directory.getUrl()).thenReturn(url);
when(directory.getConsumerUrl()).thenReturn(consumerUrl);
DemoCluster demoCluster = new DemoCluster();
- Invoker<?> invoker = demoCluster.join(directory);
+ Invoker<?> invoker = demoCluster.join(directory, true);
Assertions.assertTrue(invoker instanceof AbstractCluster.ClusterFilterInvoker);
Assertions.assertTrue(((AbstractCluster.ClusterFilterInvoker<?>) invoker).getFilterInvoker()
instanceof FilterChainBuilder.ClusterFilterChainNode);
@@ -75,8 +76,8 @@ public class AbstractClusterTest {
static class DemoCluster extends AbstractCluster {
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return super.join(directory);
+ public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
+ return super.join(directory, buildFilterChain);
}
@Override
diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java
index e17ebc1..13c9629 100644
--- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java
+++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java
@@ -27,7 +27,7 @@ public interface Cluster extends org.apache.dubbo.rpc.cluster.Cluster {
com.alibaba.dubbo.rpc.RpcException;
@Override
- default <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ default <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
return null;
}
}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index d005e38..43ab5f5 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -37,7 +37,6 @@ import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.cluster.directory.UrlStaticDirectory;
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster;
import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -52,6 +51,7 @@ import org.apache.dubbo.rpc.support.ProtocolUtils;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -403,7 +403,12 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
URL url = new ServiceConfigURL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(referenceParameters);
url = url.setScopeModel(getScopeModel());
url = url.setServiceModel(consumerModel);
- invoker = protocolSPI.refer(interfaceClass, url);
+ Invoker<?> withFilter = protocolSPI.refer(interfaceClass, url);
+
+ // Local Invoke ( Support Cluster Filter / Filter )
+ StaticDirectory<?> directory = new StaticDirectory<>(url, Collections.singletonList(withFilter));
+ invoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT).join(directory, true);
+
if (logger.isInfoEnabled()) {
logger.info("Using in jvm service " + interfaceClass.getName());
}
@@ -470,7 +475,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
if (!UrlUtils.isRegistry(curUrl)){
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(invoker);
- invoker = Cluster.getCluster(scopeModel, Cluster.DEFAULT).join(new UrlStaticDirectory(curUrl,invokers));
+ invoker = Cluster.getCluster(scopeModel, Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true);
}
} else {
List<Invoker<?>> invokers = new ArrayList<>();
@@ -492,7 +497,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
String cluster = registryUrl.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
// The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker
// (RegistryDirectory, routing happens here) -> Invoker
- invoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false).join(new StaticDirectory(registryUrl, invokers));
+ invoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false).join(new StaticDirectory(registryUrl, invokers), false);
} else {
// not a registry url, must be direct invoke.
if (CollectionUtils.isEmpty(invokers)) {
@@ -500,7 +505,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
}
URL curUrl = invokers.get(0).getUrl();
String cluster = curUrl.getParameter(CLUSTER_KEY, Cluster.DEFAULT);
- invoker = Cluster.getCluster(scopeModel, cluster).join(new UrlStaticDirectory(curUrl, invokers));
+ invoker = Cluster.getCluster(scopeModel, cluster).join(new StaticDirectory(curUrl, invokers), true);
}
}
}
@@ -589,7 +594,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
isJvmRefer = false;
} else {
// by default, reference local service if there is
- isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
+ isJvmRefer = InjvmProtocol.getInjvmProtocol(getScopeModel()).isInjvmRefer(tmpUrl);
}
} else {
isJvmRefer = isInjvm();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index 5f094b0..5d7b42c 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -16,13 +16,6 @@
*/
package org.apache.dubbo.config;
-import demo.MultiClassLoaderService;
-import demo.MultiClassLoaderServiceImpl;
-import demo.MultiClassLoaderServiceRequest;
-import demo.MultiClassLoaderServiceResult;
-import javassist.CannotCompileException;
-import javassist.CtClass;
-import javassist.NotFoundException;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.compiler.support.CtClassBuilder;
@@ -42,8 +35,10 @@ import org.apache.dubbo.registry.client.migration.MigrationInvoker;
import org.apache.dubbo.registrycenter.RegistryCenter;
import org.apache.dubbo.registrycenter.ZookeeperSingleRegistryCenter;
import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareClusterInvoker;
+import org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker;
import org.apache.dubbo.rpc.listener.ListenerInvokerWrapper;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -51,6 +46,14 @@ import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ServiceMetadata;
import org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker;
import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
+
+import demo.MultiClassLoaderService;
+import demo.MultiClassLoaderServiceImpl;
+import demo.MultiClassLoaderServiceRequest;
+import demo.MultiClassLoaderServiceResult;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.NotFoundException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -456,15 +459,15 @@ public class ReferenceConfigTest {
URL url = URL.valueOf("dubbo://127.0.0.1/DemoService")
.addParameter(INTERFACE_KEY, DemoService.class.getName());
parameters.put(INTERFACE_KEY, DemoService.class.getName());
- Exporter<?> exporter = InjvmProtocol.getInjvmProtocol().export(proxy.getInvoker(service, DemoService.class, url));
- InjvmProtocol.getInjvmProtocol().getExporterMap().put(DemoService.class.getName(), exporter);
+ Exporter<?> exporter = InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).export(proxy.getInvoker(service, DemoService.class, url));
+ InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).getExporterMap().put(DemoService.class.getName(), exporter);
Assertions.assertTrue(referenceConfig.shouldJvmRefer(parameters));
// verify that if the service has been exposed, and the cluster is configured with broadcast, local reference should not be made
parameters.put(CLUSTER_KEY, BROADCAST_CLUSTER);
Assertions.assertFalse(referenceConfig.shouldJvmRefer(parameters));
parameters.clear();
- InjvmProtocol.getInjvmProtocol().destroy();
+ InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).destroy();
}
@Test
@@ -490,9 +493,11 @@ public class ReferenceConfigTest {
.initialize();
referenceConfig.init();
- Assertions.assertTrue(referenceConfig.getInvoker() instanceof ListenerInvokerWrapper);
- Assertions.assertTrue(((ListenerInvokerWrapper<?>) referenceConfig.getInvoker()).getInvoker() instanceof InjvmInvoker);
- URL url = ((ListenerInvokerWrapper<?>) referenceConfig.getInvoker()).getInvoker().getUrl();
+ Assertions.assertTrue(referenceConfig.getInvoker() instanceof MockClusterInvoker);
+ Invoker<?> withFilter = ((MockClusterInvoker<?>) referenceConfig.getInvoker()).getDirectory().getAllInvokers().get(0);
+ Assertions.assertTrue(withFilter instanceof ListenerInvokerWrapper);
+ Assertions.assertTrue(((ListenerInvokerWrapper<?>) withFilter).getInvoker() instanceof InjvmInvoker);
+ URL url = withFilter.getUrl();
Assertions.assertEquals("application1", url.getParameter("application"));
Assertions.assertEquals("value1", url.getParameter("key1"));
Assertions.assertEquals("value2", url.getParameter("key2"));
@@ -714,14 +719,14 @@ public class ReferenceConfigTest {
DemoService service = new DemoServiceImpl();
URL url = URL.valueOf("dubbo://127.0.0.1/DemoService")
.addParameter(INTERFACE_KEY, DemoService.class.getName());
- InjvmProtocol.getInjvmProtocol().export(proxy.getInvoker(service, DemoService.class, url));
+ InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).export(proxy.getInvoker(service, DemoService.class, url));
demoService = rc.get();
success = true;
} catch (Exception e) {
// ignore
} finally {
rc.destroy();
- InjvmProtocol.getInjvmProtocol().destroy();
+ InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).destroy();
System.clearProperty("java.net.preferIPv4Stack");
}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
index 39bf974..3b5b2cc 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
@@ -23,7 +23,7 @@ import org.apache.dubbo.rpc.cluster.Directory;
public class MockCluster implements Cluster {
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {
return null;
}
}
diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml
index 164115b..b51d77b 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -795,6 +795,12 @@
META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer
</resource>
</transformer>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>
+ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil
+ </resource>
+ </transformer>
</transformers>
<filters>
<filter>
diff --git a/dubbo-native/src/main/java/org/apache/dubbo/rpc/cluster/Cluster$Adaptive.java b/dubbo-native/src/main/java/org/apache/dubbo/rpc/cluster/Cluster$Adaptive.java
index a266c82..7048752 100644
--- a/dubbo-native/src/main/java/org/apache/dubbo/rpc/cluster/Cluster$Adaptive.java
+++ b/dubbo-native/src/main/java/org/apache/dubbo/rpc/cluster/Cluster$Adaptive.java
@@ -18,7 +18,8 @@ package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
public class Cluster$Adaptive implements org.apache.dubbo.rpc.cluster.Cluster {
-public org.apache.dubbo.rpc.Invoker join(org.apache.dubbo.rpc.cluster.Directory arg0) throws org.apache.dubbo.rpc.RpcException {
+@Override
+public org.apache.dubbo.rpc.Invoker join(org.apache.dubbo.rpc.cluster.Directory arg0, boolean buildFilterChain) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.cluster.Directory argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.cluster.Directory argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
@@ -26,7 +27,7 @@ String extName = url.getParameter("cluster", "failover");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.cluster.Cluster) name from url (" + url.toString() + ") use keys([cluster])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.cluster.Cluster.class);
org.apache.dubbo.rpc.cluster.Cluster extension = (org.apache.dubbo.rpc.cluster.Cluster)scopeModel.getExtensionLoader(org.apache.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
-return extension.join(arg0);
+return extension.join(arg0, buildFilterChain);
}
public org.apache.dubbo.rpc.cluster.Cluster getCluster(java.lang.String arg0) {
throw new UnsupportedOperationException("The method public static org.apache.dubbo.rpc.cluster.Cluster org.apache.dubbo.rpc.cluster.Cluster.getCluster(java.lang.String) of interface org.apache.dubbo.rpc.cluster.Cluster is not adaptive method!");
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
index d1badc5..2257245 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
@@ -281,7 +281,7 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> {
for (List<Invoker<T>> groupList : groupMap.values()) {
StaticDirectory<T> staticDirectory = new StaticDirectory<>(groupList);
staticDirectory.buildRouterChain();
- mergedInvokers.add(cluster.join(staticDirectory));
+ mergedInvokers.add(cluster.join(staticDirectory, false));
}
} else {
mergedInvokers = invokers;
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index 404c679..d9bb2f9 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -556,7 +556,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
directory.buildRouterChain(urlToRegistry);
directory.subscribe(toSubscribeUrl(urlToRegistry));
- return (ClusterInvoker<T>) cluster.join(directory);
+ return (ClusterInvoker<T>) cluster.join(directory, true);
}
public <T> void reRefer(ClusterInvoker<?> invoker, URL newSubscribeUrl) {
diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
index 99a8da2..d16b209 100644
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocolTest.java
@@ -38,6 +38,7 @@ import org.apache.dubbo.rpc.protocol.dubbo.support.RemoteService;
import org.apache.dubbo.rpc.protocol.dubbo.support.RemoteServiceImpl;
import org.apache.dubbo.rpc.protocol.dubbo.support.Type;
import org.apache.dubbo.rpc.service.EchoService;
+
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
@@ -242,7 +243,7 @@ public class DubboProtocolTest {
Mockito.when(dic.getConsumerUrl()).thenReturn(url);
FailfastCluster cluster = new FailfastCluster();
- Invoker<DemoService> clusterInvoker = cluster.join(dic);
+ Invoker<DemoService> clusterInvoker = cluster.join(dic, true);
Result result = clusterInvoker.invoke(invocation);
Thread.sleep(10);
assertEquals(result.getValue(), "consumer");
diff --git a/dubbo-rpc/dubbo-rpc-injvm/pom.xml b/dubbo-rpc/dubbo-rpc-injvm/pom.xml
index b9f8661..3346ed0 100644
--- a/dubbo-rpc/dubbo-rpc-injvm/pom.xml
+++ b/dubbo-rpc/dubbo-rpc-injvm/pom.xml
@@ -40,5 +40,11 @@
<artifactId>dubbo-cluster</artifactId>
<version>${project.parent.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-serialization-hessian2</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/DefaultParamDeepCopyUtil.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/DefaultParamDeepCopyUtil.java
new file mode 100644
index 0000000..c2af281
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/DefaultParamDeepCopyUtil.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.injvm;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.serialize.ObjectInput;
+import org.apache.dubbo.common.serialize.ObjectOutput;
+import org.apache.dubbo.common.serialize.Serialization;
+import org.apache.dubbo.remoting.Constants;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class DefaultParamDeepCopyUtil implements ParamDeepCopyUtil {
+ private static final Logger logger = LoggerFactory.getLogger(DefaultParamDeepCopyUtil.class);
+
+ public final static String NAME = "default";
+
+ @Override
+ @SuppressWarnings({"unchecked"})
+ public <T> T copy(URL url, Object src, Class<T> targetClass) {
+ Serialization serialization = url.getOrDefaultFrameworkModel().getExtensionLoader(Serialization.class).getExtension(
+ url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION));
+
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ ObjectOutput objectOutput = serialization.serialize(url, outputStream);
+ objectOutput.writeObject(src);
+ objectOutput.flushBuffer();
+
+ try (ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray())) {
+ ObjectInput objectInput = serialization.deserialize(url, inputStream);
+ return objectInput.readObject(targetClass);
+ } catch (ClassNotFoundException | IOException e) {
+ logger.error("Unable to deep copy parameter to target class.", e);
+ }
+
+ } catch (IOException e) {
+ logger.error("Unable to deep copy parameter to target class.", e);
+ }
+
+
+ if (src.getClass().equals(targetClass)) {
+ return (T) src;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java
index 33a0775..42dbfdb 100644
--- a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java
@@ -18,6 +18,8 @@ package org.apache.dubbo.rpc.protocol.injvm;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.common.utils.ArrayUtils;
+import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Constants;
@@ -25,12 +27,17 @@ import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.FutureContext;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
+import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ServiceModel;
import org.apache.dubbo.rpc.protocol.AbstractInvoker;
+import java.lang.reflect.Type;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
@@ -49,11 +56,15 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
private final ExecutorRepository executorRepository;
+ private final ParamDeepCopyUtil paramDeepCopyUtil;
+
InjvmInvoker(Class<T> type, URL url, String key, Map<String, Exporter<?>> exporterMap) {
super(type, url);
this.key = key;
this.exporterMap = exporterMap;
this.executorRepository = url.getOrDefaultApplicationModel().getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+ this.paramDeepCopyUtil = url.getOrDefaultFrameworkModel().getExtensionLoader(ParamDeepCopyUtil.class)
+ .getExtension(url.getParameter("injvm-copy-util", DefaultParamDeepCopyUtil.NAME));
}
@Override
@@ -74,30 +85,114 @@ public class InjvmInvoker<T> extends AbstractInvoker<T> {
}
RpcContext.getServiceContext().setRemoteAddress(LOCALHOST_VALUE, 0);
// Solve local exposure, the server opens the token, and the client call fails.
- URL serverURL = exporter.getInvoker().getUrl();
+ Invoker<?> invoker = exporter.getInvoker();
+ URL serverURL = invoker.getUrl();
boolean serverHasToken = serverURL.hasParameter(Constants.TOKEN_KEY);
if (serverHasToken) {
invocation.setAttachment(Constants.TOKEN_KEY, serverURL.getParameter(Constants.TOKEN_KEY));
}
- if (isAsync(exporter.getInvoker().getUrl(), getUrl())) {
- ((RpcInvocation) invocation).setInvokeMode(InvokeMode.ASYNC);
+
+ String desc = ReflectUtils.getDesc(invocation.getParameterTypes());
+
+ // recreate invocation ---> deep copy parameters
+ Invocation copiedInvocation = recreateInvocation(invocation, invoker, desc);
+
+ if (isAsync(invoker.getUrl(), getUrl())) {
+ ((RpcInvocation) copiedInvocation).setInvokeMode(InvokeMode.ASYNC);
// use consumer executor
ExecutorService executor = executorRepository.createExecutorIfAbsent(getUrl());
CompletableFuture<AppResponse> appResponseFuture = CompletableFuture.supplyAsync(() -> {
- Result result = exporter.getInvoker().invoke(invocation);
+ Result result = invoker.invoke(copiedInvocation);
if (result.hasException()) {
return new AppResponse(result.getException());
} else {
+ rebuildValue(invocation, desc, result);
return new AppResponse(result.getValue());
}
}, executor);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
- AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, invocation);
+ AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, copiedInvocation);
result.setExecutor(executor);
return result;
} else {
- return exporter.getInvoker().invoke(invocation);
+ Result result = invoker.invoke(copiedInvocation);
+ if (result.hasException()) {
+ return result;
+ } else {
+ rebuildValue(invocation, desc, result);
+ return result;
+ }
+ }
+ }
+
+ private Class<?> getReturnType(ServiceModel consumerServiceModel, String methodName, String desc) {
+ MethodDescriptor consumerMethod = consumerServiceModel.getServiceModel().getMethod(methodName, desc);
+ if (consumerMethod != null) {
+ Type[] returnTypes = consumerMethod.getReturnTypes();
+ if (ArrayUtils.isNotEmpty(returnTypes)) {
+ return (Class<?>) returnTypes[0];
+ }
+ }
+ return null;
+ }
+
+ private Invocation recreateInvocation(Invocation invocation, Invoker<?> invoker, String desc) {
+ ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
+
+ ServiceModel providerServiceModel = invoker.getUrl().getServiceModel();
+
+ if (providerServiceModel == null) {
+ return invocation;
+ }
+ MethodDescriptor providerMethod = providerServiceModel.getServiceModel().getMethod(invocation.getMethodName(), desc);
+ Object[] realArgument = null;
+ if (providerMethod != null) {
+ Class<?>[] pts = providerMethod.getParameterClasses();
+ Object[] args = invocation.getArguments();
+
+ // switch ClassLoader
+ Thread.currentThread().setContextClassLoader(providerServiceModel.getClassLoader());
+
+ try {
+ // copy parameters
+ if (pts != null && args != null && pts.length == args.length) {
+ realArgument = new Object[pts.length];
+ for (int i = 0; i < pts.length; i++) {
+ realArgument[i] = paramDeepCopyUtil.copy(getUrl(), args[i], pts[i]);
+ }
+ }
+ if (realArgument == null) {
+ realArgument = args;
+ }
+
+ return new RpcInvocation(invocation.getServiceModel(), invocation.getMethodName(), invocation.getServiceName(), invocation.getProtocolServiceKey(),
+ pts, realArgument, new LinkedHashMap<>(invocation.getObjectAttachments()),
+ invocation.getInvoker(), invocation.getAttributes());
+ } finally {
+ Thread.currentThread().setContextClassLoader(originClassLoader);
+ }
+ } else {
+ return invocation;
+ }
+ }
+
+ private void rebuildValue(Invocation invocation, String desc, Result result) {
+ Object originValue = result.getValue();
+ Object value = originValue;
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ try {
+ ServiceModel consumerServiceModel = getUrl().getServiceModel();
+ if (consumerServiceModel != null) {
+ Class<?> returnType = getReturnType(consumerServiceModel, invocation.getMethodName(), desc);
+ if (returnType != null) {
+ Thread.currentThread().setContextClassLoader(consumerServiceModel.getClassLoader());
+ value = paramDeepCopyUtil.copy(getUrl(), originValue, returnType);
+ }
+ }
+ result.setValue(value);
+ } finally {
+ Thread.currentThread().setContextClassLoader(cl);
}
}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java
index a61220d..02db886 100644
--- a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java
@@ -17,13 +17,13 @@
package org.apache.dubbo.rpc.protocol.injvm;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.protocol.AbstractProtocol;
import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -45,17 +45,9 @@ public class InjvmProtocol extends AbstractProtocol implements Protocol {
public static final String NAME = LOCAL_PROTOCOL;
public static final int DEFAULT_PORT = 0;
- private static InjvmProtocol INSTANCE;
- public InjvmProtocol() {
- INSTANCE = this;
- }
-
- public static InjvmProtocol getInjvmProtocol() {
- if (INSTANCE == null) {
- ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(InjvmProtocol.NAME); // load
- }
- return INSTANCE;
+ public static InjvmProtocol getInjvmProtocol(ScopeModel scopeModel) {
+ return (InjvmProtocol) scopeModel.getExtensionLoader(Protocol.class).getExtension(InjvmProtocol.NAME, false);
}
static Exporter<?> getExporter(Map<String, Exporter<?>> map, URL key) {
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/ParamDeepCopyUtil.java
similarity index 64%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
copy to dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/ParamDeepCopyUtil.java
index 39bf974..c76a5a1 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/ParamDeepCopyUtil.java
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -14,16 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.mock;
+package org.apache.dubbo.rpc.protocol.injvm;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
-public class MockCluster implements Cluster {
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return null;
- }
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface ParamDeepCopyUtil {
+
+ <T> T copy(URL url, Object src, Class<T> targetClass);
}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil b/dubbo-rpc/dubbo-rpc-injvm/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil
new file mode 100644
index 0000000..59e42b8
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil
@@ -0,0 +1 @@
+default=org.apache.dubbo.rpc.protocol.injvm.DefaultParamDeepCopyUtil
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderService.java
similarity index 64%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
copy to dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderService.java
index 39bf974..5f77227 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderService.java
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -14,16 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.mock;
+package demo;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
+public interface MultiClassLoaderService {
-public class MockCluster implements Cluster {
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return null;
- }
+ Object call(MultiClassLoaderServiceRequest innerRequest);
}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceImpl.java
similarity index 51%
copy from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
copy to dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceImpl.java
index 686474f..b315aa2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceImpl.java
@@ -14,32 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.rpc.cluster.support.wrapper;
+package demo;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
+import java.util.concurrent.atomic.AtomicReference;
-/**
- * mock impl
- *
- */
-public class MockClusterWrapper implements Cluster {
-
- private final Cluster cluster;
+public class MultiClassLoaderServiceImpl implements MultiClassLoaderService {
+ private AtomicReference<MultiClassLoaderServiceRequest> innerRequestReference;
+ private AtomicReference<MultiClassLoaderServiceResult> innerResultReference;
- public MockClusterWrapper(Cluster cluster) {
- this.cluster = cluster;
+ public MultiClassLoaderServiceImpl(AtomicReference<MultiClassLoaderServiceRequest> innerRequestReference, AtomicReference<MultiClassLoaderServiceResult> innerResultReference) {
+ this.innerRequestReference = innerRequestReference;
+ this.innerResultReference = innerResultReference;
}
@Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new MockClusterInvoker<T>(directory,
- this.cluster.join(directory));
- }
-
- public Cluster getCluster() {
- return cluster;
+ public MultiClassLoaderServiceResult call(MultiClassLoaderServiceRequest innerRequest) {
+ innerRequestReference.set(innerRequest);
+ return innerResultReference.get();
}
}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceRequest.java
similarity index 64%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
copy to dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceRequest.java
index 39bf974..9dd67ca 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceRequest.java
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -14,16 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.mock;
+package demo;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
+import java.io.Serializable;
-public class MockCluster implements Cluster {
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return null;
- }
+public class MultiClassLoaderServiceRequest implements Serializable {
}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceResult.java
similarity index 64%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
copy to dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceResult.java
index 39bf974..c4ed2aa 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/demo/MultiClassLoaderServiceResult.java
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -14,16 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.mock;
+package demo;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
+import java.io.Serializable;
-public class MockCluster implements Cluster {
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return null;
- }
+public class MultiClassLoaderServiceResult implements Serializable {
}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmClassLoaderTest.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmClassLoaderTest.java
new file mode 100644
index 0000000..04e5b3b
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmClassLoaderTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.injvm;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.compiler.support.CtClassBuilder;
+import org.apache.dubbo.common.compiler.support.JavassistCompiler;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ConsumerModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.apache.dubbo.rpc.model.ProviderModel;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+
+import demo.MultiClassLoaderService;
+import demo.MultiClassLoaderServiceImpl;
+import demo.MultiClassLoaderServiceRequest;
+import demo.MultiClassLoaderServiceResult;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.NotFoundException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class InjvmClassLoaderTest {
+ @Test
+ public void testDifferentClassLoaderRequest() throws Exception {
+ String basePath = DemoService.class.getProtectionDomain().getCodeSource().getLocation().getFile();
+ basePath = java.net.URLDecoder.decode(basePath, "UTF-8");
+ TestClassLoader1 classLoader1 = new TestClassLoader1(basePath);
+ TestClassLoader1 classLoader2 = new TestClassLoader1(basePath);
+ TestClassLoader2 classLoader3 = new TestClassLoader2(classLoader2, basePath);
+
+ ApplicationConfig applicationConfig = new ApplicationConfig("TestApp");
+ ApplicationModel applicationModel = new ApplicationModel(FrameworkModel.defaultModel());
+ applicationModel.getApplicationConfigManager().setApplication(applicationConfig);
+ ModuleModel moduleModel = new ModuleModel(applicationModel);
+
+ Class clazz1 = classLoader1.loadClass(MultiClassLoaderService.class.getName(), false);
+ Class<?> clazz1impl = classLoader1.loadClass(MultiClassLoaderServiceImpl.class.getName(), false);
+ Class<?> requestClazzCustom1 = compileCustomRequest(classLoader1);
+ Class<?> resultClazzCustom1 = compileCustomResult(classLoader1);
+ classLoader1.loadedClass.put(requestClazzCustom1.getName(), requestClazzCustom1);
+ classLoader1.loadedClass.put(resultClazzCustom1.getName(), resultClazzCustom1);
+
+ // AtomicReference to cache request/response of provider
+ AtomicReference innerRequestReference = new AtomicReference();
+ AtomicReference innerResultReference = new AtomicReference();
+ innerResultReference.set(resultClazzCustom1.newInstance());
+ Constructor<?> declaredConstructor = clazz1impl.getDeclaredConstructor(AtomicReference.class, AtomicReference.class);
+
+
+ // export provider
+ ProxyFactory proxyFactory = moduleModel.getExtensionLoader(ProxyFactory.class).getExtension("javassist");
+ Protocol protocol = moduleModel.getExtensionLoader(Protocol.class).getAdaptiveExtension();
+ Object providerInstance = declaredConstructor.newInstance(innerRequestReference, innerResultReference);
+
+ URL url = URL.valueOf("injvm://localhost:0/" + MultiClassLoaderServiceImpl.class.getName() + "?interface=" + MultiClassLoaderServiceImpl.class.getName());
+ ServiceDescriptor providerServiceDescriptor = moduleModel.getServiceRepository().registerService(clazz1);
+ ProviderModel providerModel = new ProviderModel(
+ url.getServiceKey(),
+ providerInstance,
+ providerServiceDescriptor,
+ null,
+ null);
+ providerModel.setClassLoader(classLoader1);
+
+ URL providerUrl = url.setScopeModel(moduleModel).setServiceModel(providerModel);
+ Invoker invoker = proxyFactory.getInvoker(providerInstance, clazz1, providerUrl);
+ Exporter<?> exporter = protocol.export(invoker);
+
+ Class<?> clazz2 = classLoader2.loadClass(MultiClassLoaderService.class.getName(), false);
+ Class<?> requestClazzOrigin = classLoader2.loadClass(MultiClassLoaderServiceRequest.class.getName(), false);
+ Class<?> requestClazzCustom2 = compileCustomRequest(classLoader2);
+ Class<?> resultClazzCustom3 = compileCustomResult(classLoader3);
+ classLoader2.loadedClass.put(requestClazzCustom2.getName(), requestClazzCustom2);
+ classLoader3.loadedClass.put(resultClazzCustom3.getName(), resultClazzCustom3);
+
+ // refer consumer
+ ServiceDescriptor consumerServiceDescriptor = moduleModel.getServiceRepository().registerService(clazz2);
+ ConsumerModel consumerModel = new ConsumerModel(clazz2.getName(), null, consumerServiceDescriptor, null,
+ ApplicationModel.defaultModel().getDefaultModule(), null, null);
+ consumerModel.setClassLoader(classLoader3);
+ URL consumerUrl = url.setScopeModel(moduleModel).setServiceModel(consumerModel);
+
+ Object object1 = proxyFactory.getProxy(protocol.refer(clazz2, consumerUrl));
+
+ java.lang.reflect.Method callBean1 = object1.getClass().getDeclaredMethod("call", requestClazzOrigin);
+ callBean1.setAccessible(true);
+ Object result1 = callBean1.invoke(object1, requestClazzCustom2.newInstance());
+
+ // invoke result should load from classLoader3 ( sub classLoader of classLoader2 --> consumer side classLoader)
+ Assertions.assertEquals(resultClazzCustom3, result1.getClass());
+ Assertions.assertNotEquals(classLoader2, result1.getClass().getClassLoader());
+
+ // invoke reqeust param should load from classLoader1 ( provider side classLoader )
+ Assertions.assertEquals(classLoader1, innerRequestReference.get().getClass().getClassLoader());
+
+ exporter.unexport();
+ applicationModel.destroy();
+ }
+
+ private Class<?> compileCustomRequest(ClassLoader classLoader) throws NotFoundException, CannotCompileException {
+ CtClassBuilder builder = new CtClassBuilder();
+ builder.setClassName(MultiClassLoaderServiceRequest.class.getName() + "A");
+ builder.setSuperClassName(MultiClassLoaderServiceRequest.class.getName());
+ CtClass cls = builder.build(classLoader);
+ return cls.toClass(classLoader, JavassistCompiler.class.getProtectionDomain());
+ }
+
+ private Class<?> compileCustomResult(ClassLoader classLoader) throws NotFoundException, CannotCompileException {
+ CtClassBuilder builder = new CtClassBuilder();
+ builder.setClassName(MultiClassLoaderServiceResult.class.getName() + "A");
+ builder.setSuperClassName(MultiClassLoaderServiceResult.class.getName());
+ CtClass cls = builder.build(classLoader);
+ return cls.toClass(classLoader, JavassistCompiler.class.getProtectionDomain());
+ }
+
+ private static class TestClassLoader1 extends ClassLoader {
+ private String basePath;
+
+ public TestClassLoader1(String basePath) {
+ this.basePath = basePath;
+ }
+
+ Map<String, Class<?>> loadedClass = new ConcurrentHashMap<>();
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ try {
+ byte[] bytes = loadClassData(name);
+ return defineClass(name, bytes, 0, bytes.length);
+ } catch (Exception e) {
+ throw new ClassNotFoundException();
+ }
+ }
+
+ @Override
+ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (loadedClass.containsKey(name)) {
+ return loadedClass.get(name);
+ }
+ if (name.startsWith("demo")) {
+ Class<?> aClass = this.findClass(name);
+ this.loadedClass.put(name, aClass);
+ if (resolve) {
+ this.resolveClass(aClass);
+ }
+ return aClass;
+ } else {
+ Class<?> loadedClass = this.findLoadedClass(name);
+ if (loadedClass != null) {
+ return loadedClass;
+ } else {
+ return super.loadClass(name, resolve);
+ }
+ }
+ }
+
+
+ public byte[] loadClassData(String className) throws IOException {
+ className = className.replaceAll("\\.", "/");
+ String path = basePath + File.separator + className + ".class";
+ FileInputStream fileInputStream;
+ byte[] classBytes;
+ fileInputStream = new FileInputStream(path);
+ int length = fileInputStream.available();
+ classBytes = new byte[length];
+ fileInputStream.read(classBytes);
+ fileInputStream.close();
+ return classBytes;
+ }
+ }
+
+ private static class TestClassLoader2 extends ClassLoader {
+ private String basePath;
+ private TestClassLoader1 testClassLoader;
+
+ Map<String, Class<?>> loadedClass = new ConcurrentHashMap<>();
+
+ public TestClassLoader2(TestClassLoader1 testClassLoader, String basePath) {
+ this.testClassLoader = testClassLoader;
+ this.basePath = basePath;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ try {
+ byte[] bytes = loadClassData(name);
+ return defineClass(name, bytes, 0, bytes.length);
+ } catch (Exception e) {
+ throw new ClassNotFoundException();
+ }
+ }
+
+ @Override
+ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (loadedClass.containsKey(name)) {
+ return loadedClass.get(name);
+ }
+ if (name.startsWith("demo.MultiClassLoaderServiceRe")) {
+ Class<?> aClass = this.findClass(name);
+ this.loadedClass.put(name, aClass);
+ if (resolve) {
+ this.resolveClass(aClass);
+ }
+ return aClass;
+ } else {
+ return testClassLoader.loadClass(name, resolve);
+ }
+ }
+
+
+ public byte[] loadClassData(String className) throws IOException {
+ className = className.replaceAll("\\.", "/");
+ String path = basePath + File.separator + className + ".class";
+ FileInputStream fileInputStream;
+ byte[] classBytes;
+ fileInputStream = new FileInputStream(path);
+ int length = fileInputStream.available();
+ classBytes = new byte[length];
+ fileInputStream.read(classBytes);
+ fileInputStream.close();
+ return classBytes;
+ }
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmDeepCopyTest.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmDeepCopyTest.java
new file mode 100644
index 0000000..8521ebf
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmDeepCopyTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 org.apache.dubbo.rpc.protocol.injvm;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ConsumerModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.apache.dubbo.rpc.model.ProviderModel;
+import org.apache.dubbo.rpc.model.ServiceDescriptor;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.Serializable;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class InjvmDeepCopyTest {
+
+ @Test
+ public void testDeepCopy() {
+ ApplicationModel applicationModel = new ApplicationModel(FrameworkModel.defaultModel());
+ applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("TestInjvm"));
+
+ ModuleModel moduleModel = applicationModel.newModule();
+
+ AtomicReference<Data> requestReference = new AtomicReference<>();
+ AtomicReference<Data> responseReference = new AtomicReference<>();
+ Demo demo = new Demo(requestReference, responseReference);
+
+ // export provider
+ ProxyFactory proxyFactory = moduleModel.getExtensionLoader(ProxyFactory.class).getExtension("javassist");
+ Protocol protocol = moduleModel.getExtensionLoader(Protocol.class).getAdaptiveExtension();
+
+ URL url = URL.valueOf("injvm://localhost:0/" + DemoInterface.class.getName() + "?interface=" + DemoInterface.class.getName());
+ ServiceDescriptor providerServiceDescriptor = moduleModel.getServiceRepository().registerService(DemoInterface.class);
+ ProviderModel providerModel = new ProviderModel(
+ url.getServiceKey(),
+ demo,
+ providerServiceDescriptor,
+ null,
+ null);
+
+ URL providerUrl = url.setScopeModel(moduleModel).setServiceModel(providerModel);
+ Invoker invoker = proxyFactory.getInvoker(demo, DemoInterface.class, providerUrl);
+ Exporter<?> exporter = protocol.export(invoker);
+
+ // refer consumer
+ ServiceDescriptor consumerServiceDescriptor = moduleModel.getServiceRepository().registerService(DemoInterface.class);
+ ConsumerModel consumerModel = new ConsumerModel(DemoInterface.class.getName(), null, consumerServiceDescriptor, null,
+ ApplicationModel.defaultModel().getDefaultModule(), null, null);
+ URL consumerUrl = url.setScopeModel(moduleModel).setServiceModel(consumerModel);
+
+ DemoInterface stub = proxyFactory.getProxy(protocol.refer(DemoInterface.class, consumerUrl));
+
+ Data request = new Data();
+ Data response = stub.call(request);
+
+ Assertions.assertNotEquals(requestReference.get(), request);
+ Assertions.assertNotEquals(responseReference.get(), response);
+
+ exporter.unexport();
+ applicationModel.destroy();
+ }
+
+ private interface DemoInterface {
+ Data call(Data obj);
+ }
+
+ private static class Demo implements DemoInterface {
+ private AtomicReference<Data> requestReference;
+ private AtomicReference<Data> responseReference;
+
+ public Demo(AtomicReference<Data> requestReference, AtomicReference<Data> responseReference) {
+ this.requestReference = requestReference;
+ this.responseReference = responseReference;
+ }
+
+ @Override
+ public Data call(Data obj) {
+ requestReference.set(obj);
+ Data result = new Data();
+ responseReference.set(result);
+ return result;
+ }
+ }
+
+ private static class Data implements Serializable {
+
+ }
+}
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocolTest.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocolTest.java
index a35e0b3..4e57d05 100644
--- a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocolTest.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@@ -100,26 +101,26 @@ public class InjvmProtocolTest {
exporters.add(exporter);
url = url.setProtocol("dubbo");
- assertTrue(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertTrue(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = url.addParameter(GROUP_KEY, "*")
.addParameter(VERSION_KEY, "*");
- assertTrue(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertTrue(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = URL.valueOf("fake://127.0.0.1/TestService").addParameter(SCOPE_KEY, SCOPE_LOCAL);
- assertTrue(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertTrue(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = URL.valueOf("fake://127.0.0.1/TestService").addParameter(LOCAL_PROTOCOL, true);
- assertTrue(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertTrue(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = URL.valueOf("fake://127.0.0.1/TestService").addParameter(SCOPE_KEY, SCOPE_REMOTE);
- assertFalse(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertFalse(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = URL.valueOf("fake://127.0.0.1/TestService").addParameter(GENERIC_KEY, true);
- assertFalse(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertFalse(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
url = URL.valueOf("fake://127.0.0.1/TestService").addParameter("cluster", "broadcast");
- assertFalse(InjvmProtocol.getInjvmProtocol().isInjvmRefer(url));
+ assertFalse(InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).isInjvmRefer(url));
}
@Test
diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/ProtocolTest.java b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/ProtocolTest.java
index 12de553..8a53d87 100644
--- a/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/ProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-injvm/src/test/java/org/apache/dubbo/rpc/protocol/injvm/ProtocolTest.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.Test;
@@ -37,7 +38,7 @@ public class ProtocolTest {
};
static {
- InjvmProtocol injvm = InjvmProtocol.getInjvmProtocol();
+ InjvmProtocol injvm = InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel());
}
ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension("javassist");
diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/dubbo/AbstractHessian2FactoryInitializer.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/dubbo/AbstractHessian2FactoryInitializer.java
index 9d4ccf7..6bd18d2 100644
--- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/dubbo/AbstractHessian2FactoryInitializer.java
+++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/dubbo/AbstractHessian2FactoryInitializer.java
@@ -23,10 +23,23 @@ import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractHessian2FactoryInitializer implements Hessian2FactoryInitializer {
private static final Map<ClassLoader, SerializerFactory> CL_2_SERIALIZER_FACTORY = new ConcurrentHashMap<>();
+ private static volatile SerializerFactory SYSTEM_SERIALIZER_FACTORY;
@Override
public SerializerFactory getSerializerFactory() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ // system classloader
+ if (SYSTEM_SERIALIZER_FACTORY == null) {
+ synchronized (AbstractHessian2FactoryInitializer.class) {
+ if (SYSTEM_SERIALIZER_FACTORY == null) {
+ SYSTEM_SERIALIZER_FACTORY = createSerializerFactory();
+ }
+ }
+ }
+ return SYSTEM_SERIALIZER_FACTORY;
+ }
+
if (!CL_2_SERIALIZER_FACTORY.containsKey(classLoader)) {
synchronized (AbstractHessian2FactoryInitializer.class) {
if (!CL_2_SERIALIZER_FACTORY.containsKey(classLoader)) {