merge async changes in 3.x to 2.7 (#3997)
This commit is contained in:
parent
df084addc8
commit
ebafc18c4d
|
|
@ -23,11 +23,11 @@ import org.apache.dubbo.common.timer.Timeout;
|
|||
import org.apache.dubbo.common.timer.Timer;
|
||||
import org.apache.dubbo.common.timer.TimerTask;
|
||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.LoadBalance;
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
|
||||
+ e.getMessage() + ", ", e);
|
||||
addFailed(loadbalance, invocation, invokers, invoker);
|
||||
return new RpcResult(); // ignore
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,18 +18,18 @@ package org.apache.dubbo.rpc.cluster.support;
|
|||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.LoadBalance;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* When invoke fails, log the error message and ignore this error by returning an empty RpcResult.
|
||||
* When invoke fails, log the error message and ignore this error by returning an empty Result.
|
||||
* Usually used to write audit logs and other operations
|
||||
*
|
||||
* <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
|
||||
|
|
@ -50,7 +50,7 @@ public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
return invoker.invoke(invocation);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failsafe ignore exception: " + e.getMessage(), e);
|
||||
return new RpcResult(); // ignore
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
|
||||
/**
|
||||
* NOTICE! This implementation does not work well with async call.
|
||||
*
|
||||
* Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.
|
||||
*
|
||||
* <a href="http://en.wikipedia.org/wiki/Fork_(topology)">Fork</a>
|
||||
|
|
@ -70,7 +72,6 @@ public class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
} else {
|
||||
selected = new ArrayList<>();
|
||||
for (int i = 0; i < forks; i++) {
|
||||
// TODO. Add some comment here, refer chinese version for more details.
|
||||
Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
|
||||
if (!selected.contains(invoker)) {
|
||||
//Avoid add the same invoker several times.
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.NamedThreadFactory;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.LoadBalance;
|
||||
import org.apache.dubbo.rpc.cluster.Merger;
|
||||
|
|
@ -40,17 +40,16 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.MERGER_KEY;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
||||
|
||||
|
|
@ -90,26 +89,21 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
returnType = null;
|
||||
}
|
||||
|
||||
Map<String, Future<Result>> results = new HashMap<String, Future<Result>>();
|
||||
Map<String, Result> results = new HashMap<>();
|
||||
for (final Invoker<T> invoker : invokers) {
|
||||
Future<Result> future = executor.submit(new Callable<Result>() {
|
||||
@Override
|
||||
public Result call() throws Exception {
|
||||
return invoker.invoke(new RpcInvocation(invocation, invoker));
|
||||
}
|
||||
});
|
||||
results.put(invoker.getUrl().getServiceKey(), future);
|
||||
RpcInvocation subInvocation = new RpcInvocation(invocation, invoker);
|
||||
subInvocation.setAttachment(ASYNC_KEY, "true");
|
||||
results.put(invoker.getUrl().getServiceKey(), invoker.invoke(subInvocation));
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
|
||||
List<Result> resultList = new ArrayList<Result>(results.size());
|
||||
|
||||
int timeout = getUrl().getMethodParameter(invocation.getMethodName(), TIMEOUT_KEY, DEFAULT_TIMEOUT);
|
||||
for (Map.Entry<String, Future<Result>> entry : results.entrySet()) {
|
||||
Future<Result> future = entry.getValue();
|
||||
for (Map.Entry<String, Result> entry : results.entrySet()) {
|
||||
Result asyncResult = entry.getValue();
|
||||
try {
|
||||
Result r = future.get(timeout, TimeUnit.MILLISECONDS);
|
||||
Result r = asyncResult.get();
|
||||
if (r.hasException()) {
|
||||
log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) +
|
||||
" failed: " + r.getException().getMessage(),
|
||||
|
|
@ -123,13 +117,13 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
}
|
||||
|
||||
if (resultList.isEmpty()) {
|
||||
return new RpcResult((Object) null);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(invocation);
|
||||
} else if (resultList.size() == 1) {
|
||||
return resultList.iterator().next();
|
||||
}
|
||||
|
||||
if (returnType == void.class) {
|
||||
return new RpcResult((Object) null);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(invocation);
|
||||
}
|
||||
|
||||
if (merger.startsWith(".")) {
|
||||
|
|
@ -177,7 +171,7 @@ public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
|
|||
throw new RpcException("There is no merger to merge result.");
|
||||
}
|
||||
}
|
||||
return new RpcResult(result);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(result, invocation);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ 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.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.support.MockInvoker;
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ public class MockClusterInvoker<T> implements Invoker<T> {
|
|||
result = minvoker.invoke(invocation);
|
||||
} catch (RpcException me) {
|
||||
if (me.isBiz()) {
|
||||
result = new RpcResult(me.getCause());
|
||||
result = AsyncRpcResult.newDefaultAsyncResult(me.getCause(), invocation);
|
||||
} else {
|
||||
throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ package org.apache.dubbo.rpc.cluster;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -48,7 +48,7 @@ public class StickyTest {
|
|||
private Invoker<StickyTest> invoker2 = mock(Invoker.class);
|
||||
private RpcInvocation invocation;
|
||||
private Directory<StickyTest> dic;
|
||||
private Result result = new RpcResult();
|
||||
private Result result = new AppResponse();
|
||||
private StickyClusterInvoker<StickyTest> clusterinvoker = null;
|
||||
private URL url = URL.valueOf("test://test:11/test?"
|
||||
+ "&loadbalance=roundrobin"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,16 @@ public class MockDirInvocation implements Invocation {
|
|||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ package org.apache.dubbo.rpc.cluster.router.file;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.LoadBalance;
|
||||
import org.apache.dubbo.rpc.cluster.RouterFactory;
|
||||
|
|
@ -52,7 +52,7 @@ public class FileRouterEngineTest {
|
|||
Invoker<FileRouterEngineTest> invoker2 = mock(Invoker.class);
|
||||
Invocation invocation;
|
||||
StaticDirectory<FileRouterEngineTest> dic;
|
||||
Result result = new RpcResult();
|
||||
Result result = new AppResponse();
|
||||
private RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();
|
||||
|
||||
@BeforeAll
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ package org.apache.dubbo.rpc.cluster.support;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.LogUtil;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.filter.DemoService;
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ public class FailSafeClusterInvokerTest {
|
|||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
RpcInvocation invocation = new RpcInvocation();
|
||||
Directory<DemoService> dic;
|
||||
Result result = new RpcResult();
|
||||
Result result = new AppResponse();
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ package org.apache.dubbo.rpc.cluster.support;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.DubboAppender;
|
||||
import org.apache.dubbo.common.utils.LogUtil;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
|
|
@ -59,7 +59,7 @@ public class FailbackClusterInvokerTest {
|
|||
Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class);
|
||||
RpcInvocation invocation = new RpcInvocation();
|
||||
Directory<FailbackClusterInvokerTest> dic;
|
||||
Result result = new RpcResult();
|
||||
Result result = new AppResponse();
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package org.apache.dubbo.rpc.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
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.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -47,7 +47,7 @@ public class FailfastClusterInvokerTest {
|
|||
Invoker<FailfastClusterInvokerTest> invoker1 = mock(Invoker.class);
|
||||
RpcInvocation invocation = new RpcInvocation();
|
||||
Directory<FailfastClusterInvokerTest> dic;
|
||||
Result result = new RpcResult();
|
||||
Result result = new AppResponse();
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package org.apache.dubbo.rpc.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
|
||||
import org.apache.dubbo.rpc.protocol.AbstractInvoker;
|
||||
|
|
@ -55,7 +55,7 @@ public class FailoverClusterInvokerTest {
|
|||
private Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class);
|
||||
private RpcInvocation invocation = new RpcInvocation();
|
||||
private Directory<FailoverClusterInvokerTest> dic;
|
||||
private Result result = new RpcResult();
|
||||
private Result result = new AppResponse();
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package org.apache.dubbo.rpc.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
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.RpcResult;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -50,7 +50,7 @@ public class ForkingClusterInvokerTest {
|
|||
private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
|
||||
private RpcInvocation invocation = new RpcInvocation();
|
||||
private Directory<ForkingClusterInvokerTest> dic;
|
||||
private Result result = new RpcResult();
|
||||
private Result result = new AppResponse();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@
|
|||
package org.apache.dubbo.rpc.cluster.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -120,7 +121,7 @@ public class MergeableClusterInvokerTest {
|
|||
return MenuService.class;
|
||||
}
|
||||
if ("invoke".equals(method.getName())) {
|
||||
return new RpcResult(firstMenu);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(firstMenu, invocation);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -136,7 +137,7 @@ public class MergeableClusterInvokerTest {
|
|||
return MenuService.class;
|
||||
}
|
||||
if ("invoke".equals(method.getName())) {
|
||||
return new RpcResult(secondMenu);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(secondMenu, invocation);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -196,14 +197,14 @@ public class MergeableClusterInvokerTest {
|
|||
given(firstInvoker.getUrl()).willReturn(
|
||||
url.addParameter(GROUP_KEY, "first"));
|
||||
given(firstInvoker.getInterface()).willReturn(MenuService.class);
|
||||
given(firstInvoker.invoke(invocation)).willReturn(new RpcResult())
|
||||
given(firstInvoker.invoke(invocation)).willReturn(new AppResponse())
|
||||
;
|
||||
given(firstInvoker.isAvailable()).willReturn(true);
|
||||
|
||||
given(secondInvoker.getUrl()).willReturn(
|
||||
url.addParameter(GROUP_KEY, "second"));
|
||||
given(secondInvoker.getInterface()).willReturn(MenuService.class);
|
||||
given(secondInvoker.invoke(invocation)).willReturn(new RpcResult())
|
||||
given(secondInvoker.invoke(invocation)).willReturn(new AppResponse())
|
||||
;
|
||||
given(secondInvoker.isAvailable()).willReturn(true);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,62 @@ public interface RpcConstants {
|
|||
|
||||
String $INVOKE = "$invoke";
|
||||
|
||||
String $INVOKE_ASYNC = "$invokeAsync";
|
||||
|
||||
String $ECHO = "$echo";
|
||||
|
||||
String RETURN_PREFIX = "return ";
|
||||
|
||||
String THROW_PREFIX = "throw";
|
||||
|
||||
String FAIL_PREFIX = "fail:";
|
||||
|
||||
String FORCE_PREFIX = "force:";
|
||||
|
||||
String MERGER_KEY = "merger";
|
||||
|
||||
String IS_SERVER_KEY = "isserver";
|
||||
|
||||
String FORCE_USE_TAG = "dubbo.force.tag";
|
||||
|
||||
String GENERIC_SERIALIZATION_NATIVE_JAVA = "nativejava";
|
||||
|
||||
String GENERIC_SERIALIZATION_DEFAULT = "true";
|
||||
|
||||
String GENERIC_SERIALIZATION_BEAN = "bean";
|
||||
|
||||
String GENERIC_SERIALIZATION_PROTOBUF = "protobuf-json";
|
||||
|
||||
String TPS_LIMIT_RATE_KEY = "tps";
|
||||
|
||||
String TPS_LIMIT_INTERVAL_KEY = "tps.interval";
|
||||
|
||||
long DEFAULT_TPS_LIMIT_INTERVAL = 60 * 1000;
|
||||
|
||||
String AUTO_ATTACH_INVOCATIONID_KEY = "invocationid.autoattach";
|
||||
|
||||
String STUB_EVENT_KEY = "dubbo.stub.event";
|
||||
|
||||
boolean DEFAULT_STUB_EVENT = false;
|
||||
|
||||
String STUB_EVENT_METHODS_KEY = "dubbo.stub.event.methods";
|
||||
|
||||
String PROXY_KEY = "proxy";
|
||||
|
||||
String EXECUTES_KEY = "executes";
|
||||
|
||||
String REFERENCE_FILTER_KEY = "reference.filter";
|
||||
|
||||
String INVOKER_LISTENER_KEY = "invoker.listener";
|
||||
|
||||
String SERVICE_FILTER_KEY = "service.filter";
|
||||
|
||||
String EXPORTER_LISTENER_KEY = "exporter.listener";
|
||||
|
||||
String ACCESS_LOG_KEY = "accesslog";
|
||||
|
||||
String ACTIVES_KEY = "actives";
|
||||
|
||||
String CONNECTIONS_KEY = "connections";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public interface Logger {
|
|||
|
||||
/**
|
||||
* Is debug logging currently enabled?
|
||||
*
|
||||
*
|
||||
* @return true if debug is enabled
|
||||
*/
|
||||
boolean isDebugEnabled();
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.lang.reflect.GenericArrayType;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
|
|
@ -39,6 +40,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
|
@ -1096,4 +1098,25 @@ public final class ReflectUtils {
|
|||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static Type[] getReturnTypes(Method method) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
Type genericReturnType = method.getGenericReturnType();
|
||||
if (Future.class.isAssignableFrom(returnType)) {
|
||||
if (genericReturnType instanceof ParameterizedType) {
|
||||
Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
|
||||
if (actualArgType instanceof ParameterizedType) {
|
||||
returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
|
||||
genericReturnType = actualArgType;
|
||||
} else {
|
||||
returnType = (Class<?>) actualArgType;
|
||||
genericReturnType = returnType;
|
||||
}
|
||||
} else {
|
||||
returnType = null;
|
||||
genericReturnType = null;
|
||||
}
|
||||
}
|
||||
return new Type[]{returnType, genericReturnType};
|
||||
}
|
||||
}
|
||||
|
|
@ -22,12 +22,14 @@ import org.junit.jupiter.api.Test;
|
|||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
|
@ -401,6 +403,32 @@ public class ReflectUtilsTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReturnTypes () throws Exception{
|
||||
Class clazz = TypeClass.class;
|
||||
|
||||
Type[] types = ReflectUtils.getReturnTypes(clazz.getMethod("getFuture"));
|
||||
Assertions.assertEquals("java.lang.String", types[0].getTypeName());
|
||||
Assertions.assertEquals("java.lang.String", types[1].getTypeName());
|
||||
|
||||
Type[] types1 = ReflectUtils.getReturnTypes(clazz.getMethod("getString"));
|
||||
Assertions.assertEquals("java.lang.String", types1[0].getTypeName());
|
||||
Assertions.assertEquals("java.lang.String", types1[1].getTypeName());
|
||||
|
||||
Type[] types2 = ReflectUtils.getReturnTypes(clazz.getMethod("getListFuture"));
|
||||
Assertions.assertEquals("java.util.List", types2[0].getTypeName());
|
||||
Assertions.assertEquals("java.util.List<java.lang.String>", types2[1].getTypeName());
|
||||
}
|
||||
|
||||
public static interface TypeClass {
|
||||
|
||||
CompletableFuture<String> getFuture();
|
||||
|
||||
String getString();
|
||||
|
||||
CompletableFuture<List<String>> getListFuture();
|
||||
}
|
||||
|
||||
public static class EmptyClass {
|
||||
private EmptyProperty property;
|
||||
public boolean set;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setAttachmentIfAbsent(String key, String value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setAttachment(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
class CompatibleInvocation implements Invocation, org.apache.dubbo.rpc.Invocation {
|
||||
|
||||
private org.apache.dubbo.rpc.Invocation delegate;
|
||||
|
|
|
|||
|
|
@ -18,11 +18,30 @@
|
|||
package com.alibaba.dubbo.rpc;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Deprecated
|
||||
public interface Result extends org.apache.dubbo.rpc.Result {
|
||||
|
||||
class CompatibleResult implements Result {
|
||||
@Override
|
||||
default void setValue(Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setException(Throwable t) {
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractResult extends org.apache.dubbo.rpc.AbstractResult implements Result {
|
||||
|
||||
@Override
|
||||
public org.apache.dubbo.rpc.Result thenApplyWithContext(Function<org.apache.dubbo.rpc.Result, org.apache.dubbo.rpc.Result> fn) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class CompatibleResult extends AbstractResult {
|
||||
private org.apache.dubbo.rpc.Result delegate;
|
||||
|
||||
public CompatibleResult(org.apache.dubbo.rpc.Result result) {
|
||||
|
|
@ -38,11 +57,21 @@ public interface Result extends org.apache.dubbo.rpc.Result {
|
|||
return delegate.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
delegate.setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return delegate.getException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setException(Throwable t) {
|
||||
delegate.setException(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasException() {
|
||||
return delegate.hasException();
|
||||
|
|
@ -53,11 +82,6 @@ public interface Result extends org.apache.dubbo.rpc.Result {
|
|||
return delegate.recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResult() {
|
||||
return delegate.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
return delegate.getAttachments();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class RpcContext extends org.apache.dubbo.rpc.RpcContext {
|
|||
RpcContext copy = new RpcContext();
|
||||
copy.getAttachments().putAll(rpcContext.getAttachments());
|
||||
copy.get().putAll(rpcContext.get());
|
||||
copy.setFuture(rpcContext.getFuture());
|
||||
copy.setFuture(rpcContext.getCompletableFuture());
|
||||
copy.setUrls(rpcContext.getUrls());
|
||||
copy.setUrl(rpcContext.getUrl());
|
||||
copy.setMethodName(rpcContext.getMethodName());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package com.alibaba.dubbo.rpc.support;
|
|||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.rpc.Invocation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -74,10 +73,6 @@ public class RpcUtils extends org.apache.dubbo.rpc.support.RpcUtils {
|
|||
return org.apache.dubbo.rpc.support.RpcUtils.isReturnTypeFuture(inv);
|
||||
}
|
||||
|
||||
public static boolean hasFutureReturnType(Method method) {
|
||||
return org.apache.dubbo.rpc.support.RpcUtils.hasFutureReturnType(method);
|
||||
}
|
||||
|
||||
public static boolean isOneway(URL url, Invocation inv) {
|
||||
return org.apache.dubbo.rpc.support.RpcUtils.isOneway(url.getOriginalURL(), inv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
package org.apache.dubbo.filter;
|
||||
|
||||
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.service.DemoService;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
|
|
@ -58,7 +58,7 @@ public class LegacyInvoker<T> implements Invoker<T> {
|
|||
}
|
||||
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
if (hasException == false) {
|
||||
result.setValue("alibaba");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,16 @@ public class MockInvocation implements Invocation {
|
|||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachmentIfAbsent(String key, String value) {
|
||||
|
||||
}
|
||||
|
||||
public Invoker<?> getInvoker() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ import org.apache.dubbo.cache.CacheFactory;
|
|||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
|
@ -48,10 +48,10 @@ import static org.apache.dubbo.common.constants.FilterConstants.CACHE_KEY;
|
|||
* 3)<dubbo:provider cache="expiring" />
|
||||
* 4)<dubbo:consumer cache="jcache" />
|
||||
*
|
||||
* If cache type is defined in method level then method level type will get precedence. According to above provided
|
||||
* example, if service has two method, method1 and method2, method2 will have cache type as <b>threadlocal</b> where others will
|
||||
* be backed by <b>lru</b>
|
||||
* </pre>
|
||||
*If cache type is defined in method level then method level type will get precedence. According to above provided
|
||||
*example, if service has two method, method1 and method2, method2 will have cache type as <b>threadlocal</b> where others will
|
||||
*be backed by <b>lru</b>
|
||||
*</pre>
|
||||
*
|
||||
* @see org.apache.dubbo.rpc.Filter
|
||||
* @see org.apache.dubbo.cache.support.lru.LruCacheFactory
|
||||
|
|
@ -62,6 +62,7 @@ import static org.apache.dubbo.common.constants.FilterConstants.CACHE_KEY;
|
|||
* @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
|
||||
* @see org.apache.dubbo.cache.support.expiring.ExpiringCache
|
||||
*
|
||||
*/
|
||||
@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
|
||||
public class CacheFilter implements Filter {
|
||||
|
|
@ -83,7 +84,6 @@ public class CacheFilter implements Filter {
|
|||
* If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store
|
||||
* then it will return otherwise call the remote method and return value. If remote method's return valeu has error
|
||||
* then it will not cache the value.
|
||||
*
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.
|
||||
|
|
@ -98,9 +98,9 @@ public class CacheFilter implements Filter {
|
|||
Object value = cache.get(key);
|
||||
if (value != null) {
|
||||
if (value instanceof ValueWrapper) {
|
||||
return new RpcResult(((ValueWrapper) value).get());
|
||||
return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);
|
||||
} else {
|
||||
return new RpcResult(value);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
|
||||
}
|
||||
}
|
||||
Result result = invoker.invoke(invocation);
|
||||
|
|
@ -122,7 +122,7 @@ public class CacheFilter implements Filter {
|
|||
|
||||
private final Object value;
|
||||
|
||||
public ValueWrapper(Object value) {
|
||||
public ValueWrapper (Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ import org.apache.dubbo.cache.support.jcache.JCacheFactory;
|
|||
import org.apache.dubbo.cache.support.lru.LruCacheFactory;
|
||||
import org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
|
@ -60,19 +61,19 @@ public class CacheFilterTest {
|
|||
|
||||
URL url = URL.valueOf("test://test:11/test?cache=" + cacheType);
|
||||
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("value"));
|
||||
given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult("value", invocation));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
given(invoker1.invoke(invocation)).willReturn(new RpcResult("value1"));
|
||||
given(invoker1.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult("value1", invocation));
|
||||
given(invoker1.getUrl()).willReturn(url);
|
||||
|
||||
given(invoker2.invoke(invocation)).willReturn(new RpcResult("value2"));
|
||||
given(invoker2.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult("value2", invocation));
|
||||
given(invoker2.getUrl()).willReturn(url);
|
||||
|
||||
given(invoker3.invoke(invocation)).willReturn(new RpcResult(new RuntimeException()));
|
||||
given(invoker3.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(new RuntimeException(), invocation));
|
||||
given(invoker3.getUrl()).willReturn(url);
|
||||
|
||||
given(invoker4.invoke(invocation)).willReturn(new RpcResult());
|
||||
given(invoker4.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(invocation));
|
||||
given(invoker4.getUrl()).willReturn(url);
|
||||
}
|
||||
|
||||
|
|
@ -85,8 +86,8 @@ public class CacheFilterTest {
|
|||
invocation.setArguments(new Object[]{});
|
||||
|
||||
cacheFilter.invoke(invoker, invocation);
|
||||
RpcResult rpcResult1 = (RpcResult) cacheFilter.invoke(invoker1, invocation);
|
||||
RpcResult rpcResult2 = (RpcResult) cacheFilter.invoke(invoker2, invocation);
|
||||
Result rpcResult1 = cacheFilter.invoke(invoker1, invocation);
|
||||
Result rpcResult2 = cacheFilter.invoke(invoker2, invocation);
|
||||
Assertions.assertEquals(rpcResult1.getValue(), rpcResult2.getValue());
|
||||
Assertions.assertEquals(rpcResult1.getValue(), "value");
|
||||
}
|
||||
|
|
@ -100,8 +101,8 @@ public class CacheFilterTest {
|
|||
invocation.setArguments(new Object[]{"arg1"});
|
||||
|
||||
cacheFilter.invoke(invoker, invocation);
|
||||
RpcResult rpcResult1 = (RpcResult) cacheFilter.invoke(invoker1, invocation);
|
||||
RpcResult rpcResult2 = (RpcResult) cacheFilter.invoke(invoker2, invocation);
|
||||
Result rpcResult1 = cacheFilter.invoke(invoker1, invocation);
|
||||
Result rpcResult2 = cacheFilter.invoke(invoker2, invocation);
|
||||
Assertions.assertEquals(rpcResult1.getValue(), rpcResult2.getValue());
|
||||
Assertions.assertEquals(rpcResult1.getValue(), "value");
|
||||
}
|
||||
|
|
@ -115,7 +116,7 @@ public class CacheFilterTest {
|
|||
invocation.setArguments(new Object[]{"arg2"});
|
||||
|
||||
cacheFilter.invoke(invoker3, invocation);
|
||||
RpcResult rpcResult = (RpcResult) cacheFilter.invoke(invoker2, invocation);
|
||||
Result rpcResult = cacheFilter.invoke(invoker2, invocation);
|
||||
Assertions.assertEquals(rpcResult.getValue(), "value2");
|
||||
}
|
||||
|
||||
|
|
@ -128,9 +129,9 @@ public class CacheFilterTest {
|
|||
invocation.setArguments(new Object[]{"arg3"});
|
||||
|
||||
cacheFilter.invoke(invoker4, invocation);
|
||||
RpcResult rpcResult1 = (RpcResult) cacheFilter.invoke(invoker1, invocation);
|
||||
RpcResult rpcResult2 = (RpcResult) cacheFilter.invoke(invoker2, invocation);
|
||||
Assertions.assertEquals(rpcResult1.getValue(), null);
|
||||
Assertions.assertEquals(rpcResult2.getValue(), null);
|
||||
Result result1 = cacheFilter.invoke(invoker1, invocation);
|
||||
Result result2 = cacheFilter.invoke(invoker2, invocation);
|
||||
Assertions.assertEquals(result1.getValue(), null);
|
||||
Assertions.assertEquals(result2.getValue(), null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ package org.apache.dubbo.validation.filter;
|
|||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ public class ValidationFilter implements Filter {
|
|||
} catch (RpcException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
return new RpcResult(t);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(t, invocation);
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package org.apache.dubbo.validation.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.validation.Validation;
|
||||
import org.apache.dubbo.validation.Validator;
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ public class ValidationFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test?default.validation=true");
|
||||
|
||||
given(validation.getValidator(url)).willThrow(new IllegalStateException("Not found class test, cause: test"));
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("success"));
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
given(invocation.getMethodName()).willReturn("echo1");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
|
|
@ -70,7 +70,7 @@ public class ValidationFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test?default.validation=true");
|
||||
|
||||
given(validation.getValidator(url)).willReturn(validator);
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("success"));
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
given(invocation.getMethodName()).willReturn("echo1");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
|
|
@ -87,7 +87,7 @@ public class ValidationFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test");
|
||||
|
||||
given(validation.getValidator(url)).willReturn(validator);
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("success"));
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
given(invocation.getMethodName()).willReturn("echo1");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
|
|
@ -104,7 +104,7 @@ public class ValidationFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test");
|
||||
|
||||
given(validation.getValidator(url)).willReturn(validator);
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("success"));
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
given(invocation.getMethodName()).willReturn("$echo1");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
|
|
@ -124,7 +124,7 @@ public class ValidationFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test?default.validation=true");
|
||||
|
||||
given(validation.getValidator(url)).willThrow(new RpcException("rpc exception"));
|
||||
given(invoker.invoke(invocation)).willReturn(new RpcResult("success"));
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
given(invocation.getMethodName()).willReturn("echo1");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{String.class});
|
||||
|
|
|
|||
|
|
@ -88,4 +88,5 @@ public interface MonitorService {
|
|||
*/
|
||||
List<URL> lookup(URL query);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -24,9 +24,9 @@ import org.apache.dubbo.common.utils.NetUtils;
|
|||
import org.apache.dubbo.monitor.Monitor;
|
||||
import org.apache.dubbo.monitor.MonitorFactory;
|
||||
import org.apache.dubbo.monitor.MonitorService;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
|
@ -52,10 +52,14 @@ import static org.apache.dubbo.common.constants.RpcConstants.OUTPUT_KEY;
|
|||
* MonitorFilter. (SPI, Singleton, ThreadSafe)
|
||||
*/
|
||||
@Activate(group = {PROVIDER, CONSUMER})
|
||||
public class MonitorFilter implements Filter {
|
||||
public class MonitorFilter extends ListenableFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MonitorFilter.class);
|
||||
private static final String MONITOR_FILTER_START_TIME = "monitor_filter_start_time";
|
||||
|
||||
public MonitorFilter() {
|
||||
super.listener = new MonitorListener();
|
||||
}
|
||||
/**
|
||||
* The Concurrent counter
|
||||
*/
|
||||
|
|
@ -70,6 +74,7 @@ public class MonitorFilter implements Filter {
|
|||
this.monitorFactory = monitorFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The invocation interceptor,it will collect the invoke data about this invocation and send it to monitor center
|
||||
*
|
||||
|
|
@ -81,105 +86,10 @@ public class MonitorFilter implements Filter {
|
|||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
|
||||
RpcContext context = RpcContext.getContext(); // provider must fetch context before invoke() gets called
|
||||
String remoteHost = context.getRemoteHost();
|
||||
long start = System.currentTimeMillis(); // record start timestamp
|
||||
invocation.setAttachment(MONITOR_FILTER_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
getConcurrent(invoker, invocation).incrementAndGet(); // count up
|
||||
try {
|
||||
Result result = invoker.invoke(invocation); // proceed invocation chain
|
||||
collect(invoker, invocation, result, remoteHost, start, false);
|
||||
return result;
|
||||
} catch (RpcException e) {
|
||||
collect(invoker, invocation, null, remoteHost, start, true);
|
||||
throw e;
|
||||
} finally {
|
||||
getConcurrent(invoker, invocation).decrementAndGet(); // count down
|
||||
}
|
||||
} else {
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The collector logic, it will be handled by the default monitor
|
||||
*
|
||||
* @param invoker
|
||||
* @param invocation
|
||||
* @param result the invoke result
|
||||
* @param remoteHost the remote host address
|
||||
* @param start the timestamp the invoke begin
|
||||
* @param error if there is an error on the invoke
|
||||
*/
|
||||
private void collect(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
|
||||
try {
|
||||
URL monitorUrl = invoker.getUrl().getUrlParameter(MONITOR_KEY);
|
||||
Monitor monitor = monitorFactory.getMonitor(monitorUrl);
|
||||
if (monitor == null) {
|
||||
return;
|
||||
}
|
||||
URL statisticsURL = createStatisticsUrl(invoker, invocation, result, remoteHost, start, error);
|
||||
monitor.collect(statisticsURL);
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create statistics url
|
||||
*
|
||||
* @param invoker
|
||||
* @param invocation
|
||||
* @param result
|
||||
* @param remoteHost
|
||||
* @param start
|
||||
* @param error
|
||||
* @return
|
||||
*/
|
||||
private URL createStatisticsUrl(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
|
||||
// ---- service statistics ----
|
||||
long elapsed = System.currentTimeMillis() - start; // invocation cost
|
||||
int concurrent = getConcurrent(invoker, invocation).get(); // current concurrent count
|
||||
String application = invoker.getUrl().getParameter(APPLICATION_KEY);
|
||||
String service = invoker.getInterface().getName(); // service name
|
||||
String method = RpcUtils.getMethodName(invocation); // method name
|
||||
String group = invoker.getUrl().getParameter(GROUP_KEY);
|
||||
String version = invoker.getUrl().getParameter(VERSION_KEY);
|
||||
|
||||
int localPort;
|
||||
String remoteKey, remoteValue;
|
||||
if (CONSUMER_SIDE.equals(invoker.getUrl().getParameter(SIDE_KEY))) {
|
||||
// ---- for service consumer ----
|
||||
localPort = 0;
|
||||
remoteKey = MonitorService.PROVIDER;
|
||||
remoteValue = invoker.getUrl().getAddress();
|
||||
} else {
|
||||
// ---- for service provider ----
|
||||
localPort = invoker.getUrl().getPort();
|
||||
remoteKey = MonitorService.CONSUMER;
|
||||
remoteValue = remoteHost;
|
||||
}
|
||||
String input = "", output = "";
|
||||
if (invocation.getAttachment(INPUT_KEY) != null) {
|
||||
input = invocation.getAttachment(INPUT_KEY);
|
||||
}
|
||||
if (result != null && result.getAttachment(OUTPUT_KEY) != null) {
|
||||
output = result.getAttachment(OUTPUT_KEY);
|
||||
}
|
||||
|
||||
return new URL(COUNT_PROTOCOL,
|
||||
NetUtils.getLocalHost(), localPort,
|
||||
service + PATH_SEPARATOR + method,
|
||||
MonitorService.APPLICATION, application,
|
||||
MonitorService.INTERFACE, service,
|
||||
MonitorService.METHOD, method,
|
||||
remoteKey, remoteValue,
|
||||
error ? MonitorService.FAILURE : MonitorService.SUCCESS, "1",
|
||||
MonitorService.ELAPSED, String.valueOf(elapsed),
|
||||
MonitorService.CONCURRENT, String.valueOf(concurrent),
|
||||
INPUT_KEY, input,
|
||||
OUTPUT_KEY, output,
|
||||
GROUP_KEY, group,
|
||||
VERSION_KEY, version);
|
||||
return invoker.invoke(invocation); // proceed invocation chain
|
||||
}
|
||||
|
||||
// concurrent counter
|
||||
|
|
@ -193,4 +103,93 @@ public class MonitorFilter implements Filter {
|
|||
return concurrent;
|
||||
}
|
||||
|
||||
class MonitorListener implements Listener {
|
||||
|
||||
@Override
|
||||
public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
|
||||
collect(invoker, invocation, result, RpcContext.getContext().getRemoteHost(), Long.valueOf(invocation.getAttachment(MONITOR_FILTER_START_TIME)), false);
|
||||
getConcurrent(invoker, invocation).decrementAndGet(); // count down
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
|
||||
collect(invoker, invocation, null, RpcContext.getContext().getRemoteHost(), Long.valueOf(invocation.getAttachment(MONITOR_FILTER_START_TIME)), true);
|
||||
getConcurrent(invoker, invocation).decrementAndGet(); // count down
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The collector logic, it will be handled by the default monitor
|
||||
*
|
||||
* @param invoker
|
||||
* @param invocation
|
||||
* @param result the invoke result
|
||||
* @param remoteHost the remote host address
|
||||
* @param start the timestamp the invoke begin
|
||||
* @param error if there is an error on the invoke
|
||||
*/
|
||||
private void collect(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
|
||||
try {
|
||||
URL monitorUrl = invoker.getUrl().getUrlParameter(MONITOR_KEY);
|
||||
Monitor monitor = monitorFactory.getMonitor(monitorUrl);
|
||||
if (monitor == null) {
|
||||
return;
|
||||
}
|
||||
URL statisticsURL = createStatisticsUrl(invoker, invocation, result, remoteHost, start, error);
|
||||
monitor.collect(statisticsURL);
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create statistics url
|
||||
*
|
||||
* @param invoker
|
||||
* @param invocation
|
||||
* @param result
|
||||
* @param remoteHost
|
||||
* @param start
|
||||
* @param error
|
||||
* @return
|
||||
*/
|
||||
private URL createStatisticsUrl(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {
|
||||
// ---- service statistics ----
|
||||
long elapsed = System.currentTimeMillis() - start; // invocation cost
|
||||
int concurrent = getConcurrent(invoker, invocation).get(); // current concurrent count
|
||||
String application = invoker.getUrl().getParameter(APPLICATION_KEY);
|
||||
String service = invoker.getInterface().getName(); // service name
|
||||
String method = RpcUtils.getMethodName(invocation); // method name
|
||||
String group = invoker.getUrl().getParameter(GROUP_KEY);
|
||||
String version = invoker.getUrl().getParameter(VERSION_KEY);
|
||||
|
||||
int localPort;
|
||||
String remoteKey, remoteValue;
|
||||
if (CONSUMER_SIDE.equals(invoker.getUrl().getParameter(SIDE_KEY))) {
|
||||
// ---- for service consumer ----
|
||||
localPort = 0;
|
||||
remoteKey = MonitorService.PROVIDER;
|
||||
remoteValue = invoker.getUrl().getAddress();
|
||||
} else {
|
||||
// ---- for service provider ----
|
||||
localPort = invoker.getUrl().getPort();
|
||||
remoteKey = MonitorService.CONSUMER;
|
||||
remoteValue = remoteHost;
|
||||
}
|
||||
String input = "", output = "";
|
||||
if (invocation.getAttachment(INPUT_KEY) != null) {
|
||||
input = invocation.getAttachment(INPUT_KEY);
|
||||
}
|
||||
if (result != null && result.getAttachment(OUTPUT_KEY) != null) {
|
||||
output = result.getAttachment(OUTPUT_KEY);
|
||||
}
|
||||
|
||||
return new URL(COUNT_PROTOCOL, NetUtils.getLocalHost(), localPort, service + PATH_SEPARATOR + method, MonitorService.APPLICATION, application, MonitorService.INTERFACE, service, MonitorService.METHOD, method, remoteKey, remoteValue, error ? MonitorService.FAILURE : MonitorService.SUCCESS, "1", MonitorService.ELAPSED, String.valueOf(elapsed), MonitorService.CONCURRENT, String.valueOf(concurrent), INPUT_KEY, input, OUTPUT_KEY, output, GROUP_KEY, group, VERSION_KEY, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.NetUtils;
|
|||
import org.apache.dubbo.monitor.Monitor;
|
||||
import org.apache.dubbo.monitor.MonitorFactory;
|
||||
import org.apache.dubbo.monitor.MonitorService;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
|
|
@ -77,7 +78,7 @@ public class MonitorFilterTest {
|
|||
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
lastInvocation = invocation;
|
||||
return null;
|
||||
return AsyncRpcResult.newDefaultAsyncResult(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -119,7 +120,11 @@ public class MonitorFilterTest {
|
|||
monitorFilter.setMonitorFactory(monitorFactory);
|
||||
Invocation invocation = new RpcInvocation("aaa", new Class<?>[0], new Object[0]);
|
||||
RpcContext.getContext().setRemoteAddress(NetUtils.getLocalHost(), 20880).setLocalAddress(NetUtils.getLocalHost(), 2345);
|
||||
monitorFilter.invoke(serviceInvoker, invocation);
|
||||
Result result = monitorFilter.invoke(serviceInvoker, invocation);
|
||||
result.thenApplyWithContext((r) -> {
|
||||
monitorFilter.listener().onResponse(r, serviceInvoker, invocation);
|
||||
return r;
|
||||
});
|
||||
while (lastStatistics == null) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
|
@ -155,7 +160,11 @@ public class MonitorFilterTest {
|
|||
monitorFilter.setMonitorFactory(monitorFactory);
|
||||
Invocation invocation = new RpcInvocation("$invoke", new Class<?>[]{String.class, String[].class, Object[].class}, new Object[]{"xxx", new String[]{}, new Object[]{}});
|
||||
RpcContext.getContext().setRemoteAddress(NetUtils.getLocalHost(), 20880).setLocalAddress(NetUtils.getLocalHost(), 2345);
|
||||
monitorFilter.invoke(serviceInvoker, invocation);
|
||||
Result result = monitorFilter.invoke(serviceInvoker, invocation);
|
||||
result.thenApplyWithContext((r) -> {
|
||||
monitorFilter.listener().onResponse(r, serviceInvoker, invocation);
|
||||
return r;
|
||||
});
|
||||
while (lastStatistics == null) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import org.apache.dubbo.common.logger.LoggerFactory;
|
|||
import org.apache.dubbo.common.store.DataStore;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.monitor.MetricsService;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
|
|
@ -31,7 +31,6 @@ import org.apache.dubbo.rpc.Protocol;
|
|||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
|
@ -66,6 +65,7 @@ import static org.apache.dubbo.monitor.Constants.METHOD;
|
|||
import static org.apache.dubbo.monitor.Constants.METRICS_PORT;
|
||||
import static org.apache.dubbo.monitor.Constants.METRICS_PROTOCOL;
|
||||
import static org.apache.dubbo.monitor.Constants.SERVICE;
|
||||
import static org.apache.dubbo.remoting.Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
|
||||
|
||||
public class MetricsFilter implements Filter {
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ public class MetricsFilter implements Filter {
|
|||
|
||||
private List<MetricObject> getThreadPoolMessage() {
|
||||
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
|
||||
Map<String, Object> executors = dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY);
|
||||
Map<String, Object> executors = dataStore.get(EXECUTOR_SERVICE_COMPONENT_KEY);
|
||||
|
||||
List<MetricObject> threadPoolMtricList = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : executors.entrySet()) {
|
||||
|
|
@ -235,12 +235,9 @@ public class MetricsFilter implements Filter {
|
|||
collector.collect(entry.getKey(), entry.getValue(), timestamp);
|
||||
}
|
||||
|
||||
RpcResult result = new RpcResult();
|
||||
|
||||
List res = collector.build();
|
||||
res.addAll(getThreadPoolMessage());
|
||||
result.setValue(JSON.toJSONString(res));
|
||||
return result;
|
||||
return AsyncRpcResult.newDefaultAsyncResult(JSON.toJSONString(res), invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ import org.apache.dubbo.remoting.ChannelHandler;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class MockChannel implements ExchangeChannel {
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ public class MockChannel implements ExchangeChannel {
|
|||
return null;
|
||||
}
|
||||
|
||||
public ResponseFuture send(Object request, int timeout) throws RemotingException {
|
||||
public CompletableFuture<Object> send(Object request, int timeout) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -85,11 +85,11 @@ public class MockChannel implements ExchangeChannel {
|
|||
return null;
|
||||
}
|
||||
|
||||
public ResponseFuture request(Object request) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ResponseFuture request(Object request, int timeout) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ import org.apache.dubbo.remoting.Codec;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeClient;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseCallback;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* MockedClient
|
||||
|
|
@ -79,27 +80,24 @@ public class MockedClient implements ExchangeClient {
|
|||
this.sent = msg;
|
||||
}
|
||||
|
||||
public ResponseFuture request(Object msg) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object msg) throws RemotingException {
|
||||
return request(msg, 0);
|
||||
}
|
||||
|
||||
public ResponseFuture request(Object msg, int timeout) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object msg, int timeout) throws RemotingException {
|
||||
this.invoked = msg;
|
||||
return new ResponseFuture() {
|
||||
public Object get() throws RemotingException {
|
||||
return new CompletableFuture<Object>() {
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
return received;
|
||||
}
|
||||
|
||||
public Object get(int timeoutInMillis) throws RemotingException {
|
||||
public Object get(int timeoutInMillis) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return received;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCallback(ResponseCallback callback) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<javax.ws.rs.version>2.1</javax.ws.rs.version>
|
||||
<argline>-Dnetwork_interface_denylist=docker0</argline>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ import java.net.InetSocketAddress;
|
|||
* RemotingException. (API, Prototype, ThreadSafe)
|
||||
*
|
||||
* @export
|
||||
* @see org.apache.dubbo.remoting.exchange.ResponseFuture#get()
|
||||
* @see org.apache.dubbo.remoting.exchange.ResponseFuture#get(int)
|
||||
* @see org.apache.dubbo.remoting.exchange.support.DefaultFuture#get()
|
||||
* @see org.apache.dubbo.remoting.Channel#send(Object, boolean)
|
||||
* @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object)
|
||||
* @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object, int)
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ import java.net.InetSocketAddress;
|
|||
* TimeoutException. (API, Prototype, ThreadSafe)
|
||||
*
|
||||
* @export
|
||||
* @see org.apache.dubbo.remoting.exchange.ResponseFuture#get()
|
||||
* @see org.apache.dubbo.remoting.exchange.ResponseFuture#get(int)
|
||||
* @see org.apache.dubbo.remoting.exchange.support.DefaultFuture#get()
|
||||
*/
|
||||
public class TimeoutException extends RemotingException {
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package org.apache.dubbo.remoting.exchange;
|
|||
import org.apache.dubbo.remoting.Channel;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* ExchangeChannel. (API/SPI, Prototype, ThreadSafe)
|
||||
*/
|
||||
|
|
@ -31,7 +33,7 @@ public interface ExchangeChannel extends Channel {
|
|||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
ResponseFuture request(Object request) throws RemotingException;
|
||||
CompletableFuture<Object> request(Object request) throws RemotingException;
|
||||
|
||||
/**
|
||||
* send request.
|
||||
|
|
@ -41,7 +43,7 @@ public interface ExchangeChannel extends Channel {
|
|||
* @return response future
|
||||
* @throws RemotingException
|
||||
*/
|
||||
ResponseFuture request(Object request, int timeout) throws RemotingException;
|
||||
CompletableFuture<Object> request(Object request, int timeout) throws RemotingException;
|
||||
|
||||
/**
|
||||
* get message handler.
|
||||
|
|
|
|||
|
|
@ -1,38 +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.remoting.exchange;
|
||||
|
||||
/**
|
||||
* Callback
|
||||
*/
|
||||
public interface ResponseCallback {
|
||||
|
||||
/**
|
||||
* done.
|
||||
*
|
||||
* @param response
|
||||
*/
|
||||
void done(Object response);
|
||||
|
||||
/**
|
||||
* caught exception.
|
||||
*
|
||||
* @param exception
|
||||
*/
|
||||
void caught(Throwable exception);
|
||||
|
||||
}
|
||||
|
|
@ -1,58 +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.remoting.exchange;
|
||||
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
|
||||
/**
|
||||
* Future. (API/SPI, Prototype, ThreadSafe)
|
||||
*
|
||||
* @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object)
|
||||
* @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object, int)
|
||||
*/
|
||||
public interface ResponseFuture {
|
||||
|
||||
/**
|
||||
* get result.
|
||||
*
|
||||
* @return result.
|
||||
*/
|
||||
Object get() throws RemotingException;
|
||||
|
||||
/**
|
||||
* get result with the specified timeout.
|
||||
*
|
||||
* @param timeoutInMillis timeout.
|
||||
* @return result.
|
||||
*/
|
||||
Object get(int timeoutInMillis) throws RemotingException;
|
||||
|
||||
/**
|
||||
* set callback.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void setCallback(ResponseCallback callback);
|
||||
|
||||
/**
|
||||
* check is done.
|
||||
*
|
||||
* @return done or not.
|
||||
*/
|
||||
boolean isDone();
|
||||
|
||||
}
|
||||
|
|
@ -28,17 +28,13 @@ import org.apache.dubbo.remoting.RemotingException;
|
|||
import org.apache.dubbo.remoting.TimeoutException;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseCallback;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
|
|
@ -46,7 +42,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
|||
/**
|
||||
* DefaultFuture.
|
||||
*/
|
||||
public class DefaultFuture implements ResponseFuture {
|
||||
public class DefaultFuture extends CompletableFuture<Object> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultFuture.class);
|
||||
|
||||
|
|
@ -66,12 +62,8 @@ public class DefaultFuture implements ResponseFuture {
|
|||
private final Channel channel;
|
||||
private final Request request;
|
||||
private final int timeout;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Condition done = lock.newCondition();
|
||||
private final long start = System.currentTimeMillis();
|
||||
private volatile long sent;
|
||||
private volatile Response response;
|
||||
private volatile ResponseCallback callback;
|
||||
|
||||
private DefaultFuture(Channel channel, Request request, int timeout) {
|
||||
this.channel = channel;
|
||||
|
|
@ -170,142 +162,32 @@ public class DefaultFuture implements ResponseFuture {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object get() throws RemotingException {
|
||||
return get(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int timeout) throws RemotingException {
|
||||
if (timeout <= 0) {
|
||||
timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
if (!isDone()) {
|
||||
long start = System.currentTimeMillis();
|
||||
lock.lock();
|
||||
try {
|
||||
while (!isDone()) {
|
||||
done.await(timeout, TimeUnit.MILLISECONDS);
|
||||
if (isDone() || System.currentTimeMillis() - start > timeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (!isDone()) {
|
||||
throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
|
||||
}
|
||||
}
|
||||
return returnFromResponse();
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
Response errorResult = new Response(id);
|
||||
errorResult.setStatus(Response.CLIENT_ERROR);
|
||||
errorResult.setErrorMessage("request future has been canceled.");
|
||||
this.doReceived(errorResult);
|
||||
FUTURES.remove(id);
|
||||
CHANNELS.remove(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
Response errorResult = new Response(id);
|
||||
errorResult.setErrorMessage("request future has been canceled.");
|
||||
response = errorResult;
|
||||
FUTURES.remove(id);
|
||||
CHANNELS.remove(id);
|
||||
this.cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return response != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(ResponseCallback callback) {
|
||||
if (isDone()) {
|
||||
invokeCallback(callback);
|
||||
} else {
|
||||
boolean isdone = false;
|
||||
lock.lock();
|
||||
try {
|
||||
if (!isDone()) {
|
||||
this.callback = callback;
|
||||
} else {
|
||||
isdone = true;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (isdone) {
|
||||
invokeCallback(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TimeoutCheckTask implements TimerTask {
|
||||
|
||||
private DefaultFuture future;
|
||||
|
||||
TimeoutCheckTask(DefaultFuture future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Timeout timeout) {
|
||||
// remove from pending task
|
||||
PENDING_TASKS.remove(future.getId());
|
||||
|
||||
if (future.isDone()) {
|
||||
return;
|
||||
}
|
||||
// create exception response.
|
||||
Response timeoutResponse = new Response(future.getId());
|
||||
// set timeout status.
|
||||
timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT);
|
||||
timeoutResponse.setErrorMessage(future.getTimeoutMessage(true));
|
||||
// handle response.
|
||||
DefaultFuture.received(future.getChannel(), timeoutResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeCallback(ResponseCallback c) {
|
||||
if (c == null) {
|
||||
throw new NullPointerException("callback cannot be null.");
|
||||
}
|
||||
Response res = response;
|
||||
if (res == null) {
|
||||
throw new IllegalStateException("response cannot be null. url:" + channel.getUrl());
|
||||
}
|
||||
|
||||
if (res.getStatus() == Response.OK) {
|
||||
try {
|
||||
c.done(res.getResult());
|
||||
} catch (Exception e) {
|
||||
logger.error("callback invoke error .result:" + res.getResult() + ",url:" + channel.getUrl(), e);
|
||||
}
|
||||
} else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
|
||||
try {
|
||||
TimeoutException te = new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
|
||||
c.caught(te);
|
||||
} catch (Exception e) {
|
||||
logger.error("callback invoke error ,url:" + channel.getUrl(), e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
RuntimeException re = new RuntimeException(res.getErrorMessage());
|
||||
c.caught(re);
|
||||
} catch (Exception e) {
|
||||
logger.error("callback invoke error ,url:" + channel.getUrl(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object returnFromResponse() throws RemotingException {
|
||||
Response res = response;
|
||||
private void doReceived(Response res) {
|
||||
if (res == null) {
|
||||
throw new IllegalStateException("response cannot be null");
|
||||
}
|
||||
if (res.getStatus() == Response.OK) {
|
||||
return res.getResult();
|
||||
this.complete(res.getResult());
|
||||
} else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
|
||||
this.completeExceptionally(new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()));
|
||||
} else {
|
||||
this.completeExceptionally(new RemotingException(channel, res.getErrorMessage()));
|
||||
}
|
||||
if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
|
||||
throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
|
||||
}
|
||||
throw new RemotingException(channel, res.getErrorMessage());
|
||||
}
|
||||
|
||||
private long getId() {
|
||||
|
|
@ -328,27 +210,10 @@ public class DefaultFuture implements ResponseFuture {
|
|||
return timeout;
|
||||
}
|
||||
|
||||
private long getStartTimestamp() {
|
||||
return start;
|
||||
}
|
||||
|
||||
private void doSent() {
|
||||
sent = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void doReceived(Response res) {
|
||||
lock.lock();
|
||||
try {
|
||||
response = res;
|
||||
done.signalAll();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
if (callback != null) {
|
||||
invokeCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private String getTimeoutMessage(boolean scan) {
|
||||
long nowTimestamp = System.currentTimeMillis();
|
||||
return (sent > 0 ? "Waiting server-side response timeout" : "Sending request timeout in client-side")
|
||||
|
|
@ -361,4 +226,28 @@ public class DefaultFuture implements ResponseFuture {
|
|||
+ timeout + " ms, request: " + request + ", channel: " + channel.getLocalAddress()
|
||||
+ " -> " + channel.getRemoteAddress();
|
||||
}
|
||||
|
||||
private static class TimeoutCheckTask implements TimerTask {
|
||||
|
||||
private DefaultFuture future;
|
||||
|
||||
TimeoutCheckTask(DefaultFuture future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Timeout timeout) {
|
||||
if (future == null || future.isDone()) {
|
||||
return;
|
||||
}
|
||||
// create exception response.
|
||||
Response timeoutResponse = new Response(future.getId());
|
||||
// set timeout status.
|
||||
timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT);
|
||||
timeoutResponse.setErrorMessage(future.getTimeoutMessage(true));
|
||||
// handle response.
|
||||
DefaultFuture.received(future.getChannel(), timeoutResponse);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +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.remoting.exchange.support;
|
||||
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseCallback;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
|
||||
/**
|
||||
* SimpleFuture
|
||||
*/
|
||||
public class SimpleFuture implements ResponseFuture {
|
||||
|
||||
private final Object value;
|
||||
|
||||
public SimpleFuture(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() throws RemotingException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int timeoutInMillis) throws RemotingException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(ResponseCallback callback) {
|
||||
callback.done(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,10 +27,10 @@ import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
|||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
import org.apache.dubbo.remoting.exchange.Request;
|
||||
import org.apache.dubbo.remoting.exchange.Response;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
|
|
@ -99,12 +99,12 @@ final class HeaderExchangeChannel implements ExchangeChannel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResponseFuture request(Object request) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request) throws RemotingException {
|
||||
return request(request, channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseFuture request(Object request, int timeout) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
|
||||
if (closed) {
|
||||
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ import org.apache.dubbo.remoting.RemotingException;
|
|||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeClient;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.dubbo.common.utils.UrlUtils.getHeartbeat;
|
||||
|
|
@ -65,7 +65,7 @@ public class HeaderExchangeClient implements ExchangeClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResponseFuture request(Object request) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request) throws RemotingException {
|
||||
return channel.request(request);
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ public class HeaderExchangeClient implements ExchangeClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResponseFuture request(Object request, int timeout) throws RemotingException {
|
||||
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
|
||||
return channel.request(request, timeout);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
|
|||
import org.apache.dubbo.remoting.transport.ChannelHandlerDelegate;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -99,19 +99,12 @@ public class HeaderExchangeHandler implements ChannelHandlerDelegate {
|
|||
// find handler by message class.
|
||||
Object msg = req.getData();
|
||||
try {
|
||||
// handle data.
|
||||
CompletableFuture<Object> future = handler.reply(channel, msg);
|
||||
if (future.isDone()) {
|
||||
res.setStatus(Response.OK);
|
||||
res.setResult(future.get());
|
||||
channel.send(res);
|
||||
return;
|
||||
}
|
||||
future.whenComplete((result, t) -> {
|
||||
CompletionStage<Object> future = handler.reply(channel, msg);
|
||||
future.whenComplete((appResult, t) -> {
|
||||
try {
|
||||
if (t == null) {
|
||||
res.setStatus(Response.OK);
|
||||
res.setResult(result);
|
||||
res.setResult(appResult);
|
||||
} else {
|
||||
res.setStatus(Response.SERVICE_ERROR);
|
||||
res.setErrorMessage(StringUtils.toString(t));
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ package org.apache.dubbo.remoting;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.Exchangers;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
import org.apache.dubbo.remoting.exchange.support.ReplierDispatcher;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ public class Main {
|
|||
|
||||
System.out.println("=====test invoke=====");
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ResponseFuture future = client.request(new Main.Data());
|
||||
CompletableFuture<Object> future = client.request(new Main.Data());
|
||||
System.out.println("invoke and get");
|
||||
System.out.println("invoke result:" + future.get());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package org.apache.dubbo.remoting;
|
|||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* RpcResult.
|
||||
* AppResponse.
|
||||
*/
|
||||
|
||||
public class MockResult implements Serializable {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class DefaultFutureTest {
|
|||
try {
|
||||
f.get();
|
||||
} catch (Exception e) {
|
||||
Assertions.assertTrue(e instanceof TimeoutException, "catch exception is not timeout exception!");
|
||||
Assertions.assertTrue(e.getCause() instanceof TimeoutException, "catch exception is not timeout exception!");
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ public class DefaultFutureTest {
|
|||
try {
|
||||
f.get();
|
||||
} catch (Exception e) {
|
||||
Assertions.assertTrue(e instanceof TimeoutException, "catch exception is not timeout exception!");
|
||||
Assertions.assertTrue(e.getCause() instanceof TimeoutException, "catch exception is not timeout exception!");
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ public class HeaderExchangeHandlerTest {
|
|||
HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(new MockedExchangeHandler() {
|
||||
|
||||
@Override
|
||||
public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException {
|
||||
public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {
|
||||
Assertions.fail();
|
||||
throw new RemotingException(channel, "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.apache.remoting.transport.mina;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeServer;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
|
@ -27,6 +26,8 @@ import org.junit.jupiter.api.Assertions;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* ClientToServer
|
||||
*/
|
||||
|
|
@ -64,7 +65,7 @@ public abstract class ClientToServerTest {
|
|||
|
||||
@Test
|
||||
public void testFuture() throws Exception {
|
||||
ResponseFuture future = client.request(new World("world"));
|
||||
CompletableFuture<Object> future = client.request(new World("world"));
|
||||
Hello result = (Hello) future.get();
|
||||
Assertions.assertEquals("hello,world", result.getName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
|
|||
import org.apache.dubbo.remoting.exchange.ExchangeServer;
|
||||
import org.apache.dubbo.remoting.exchange.Exchangers;
|
||||
import org.apache.dubbo.remoting.transport.dispatcher.FakeChannelHandlers;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@ package org.apache.dubbo.remoting.transport.netty;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeServer;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* ClientToServer
|
||||
*/
|
||||
|
|
@ -64,7 +64,7 @@ public abstract class ClientToServerTest {
|
|||
|
||||
@Test
|
||||
public void testFuture() throws Exception {
|
||||
ResponseFuture future = client.request(new World("world"));
|
||||
CompletableFuture<Object> future = client.request(new World("world"));
|
||||
Hello result = (Hello) future.get();
|
||||
Assertions.assertEquals("hello,world", result.getName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.apache.dubbo.remoting.transport.netty4;
|
|||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeChannel;
|
||||
import org.apache.dubbo.remoting.exchange.ExchangeServer;
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
import org.apache.dubbo.remoting.exchange.support.Replier;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
|
@ -27,6 +26,8 @@ import org.junit.jupiter.api.Assertions;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* ClientToServer
|
||||
*/
|
||||
|
|
@ -64,7 +65,7 @@ public abstract class ClientToServerTest {
|
|||
|
||||
@Test
|
||||
public void testFuture() throws Exception {
|
||||
ResponseFuture future = client.request(new World("world"));
|
||||
CompletableFuture<Object> future = client.request(new World("world"));
|
||||
Hello result = (Hello) future.get();
|
||||
Assertions.assertEquals("hello,world", result.getName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,59 +16,10 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc;
|
||||
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractResult implements Result {
|
||||
protected Map<String, String> attachments = new HashMap<String, String>();
|
||||
|
||||
protected Object result;
|
||||
|
||||
protected Throwable exception;
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
this.attachments = map == null ? new HashMap<String, String>() : map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
if (this.attachments == null) {
|
||||
this.attachments = new HashMap<String, String>();
|
||||
}
|
||||
this.attachments.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
return attachments.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
String result = attachments.get(key);
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
result = defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
attachments.put(key, value);
|
||||
}
|
||||
|
||||
public abstract class AbstractResult extends CompletableFuture<Result> implements Result {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* {@link AsyncRpcResult} is introduced in 3.0.0 to replace RpcResult, and RpcResult is replaced with {@link AppResponse}:
|
||||
* <ul>
|
||||
* <li>AsyncRpcResult is the object that is actually passed in the call chain</li>
|
||||
* <li>AppResponse only simply represents the business result</li>
|
||||
* </ul>
|
||||
*
|
||||
* The relationship between them can be described as follow, an abstraction of the definition of AsyncRpcResult:
|
||||
* <pre>
|
||||
* {@code
|
||||
* Public class AsyncRpcResult implements CompletionStage<AppResponse> {
|
||||
* ......
|
||||
* }
|
||||
* </pre>
|
||||
* AsyncRpcResult is a future representing an unfinished RPC call, while AppResponse is the actual return type of this call.
|
||||
* In theory, AppResponse does'n have to implement the {@link Result} interface, this is done mainly for compatibility purpose.
|
||||
*
|
||||
* @serial Do not change the class name and properties.
|
||||
*/
|
||||
public class AppResponse extends AbstractResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6925924956850004727L;
|
||||
|
||||
private Object result;
|
||||
|
||||
private Throwable exception;
|
||||
|
||||
private Map<String, String> attachments = new HashMap<String, String>();
|
||||
|
||||
public AppResponse() {
|
||||
}
|
||||
|
||||
public AppResponse(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public AppResponse(Throwable exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object recreate() throws Throwable {
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.result = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public void setException(Throwable e) {
|
||||
this.exception = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasException() {
|
||||
return exception != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append all items from the map into the attachment, if map is empty then nothing happens
|
||||
*
|
||||
* @param map contains all key-value pairs to append
|
||||
*/
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
this.attachments = map == null ? new HashMap<String, String>() : map;
|
||||
}
|
||||
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
if (this.attachments == null) {
|
||||
this.attachments = new HashMap<String, String>();
|
||||
}
|
||||
this.attachments.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
return attachments.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
String result = attachments.get(key);
|
||||
if (result == null || result.length() == 0) {
|
||||
result = defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setAttachment(String key, String value) {
|
||||
attachments.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result thenApplyWithContext(Function<Result, Result> fn) {
|
||||
throw new UnsupportedOperationException("AppResponse represents an concrete business response, there will be no status changes, you should get internal values directly.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppResponse [value=" + result + ", exception=" + exception + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -25,176 +25,174 @@ import java.util.concurrent.CompletionException;
|
|||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* <b>NOTICE!!</b>
|
||||
*
|
||||
* This class represents an unfinished RPC call, it will hold some context information for this call, for example RpcContext and Invocation,
|
||||
* so that when the call finishes and the result returns, it can guarantee all the contexts being recovered as the same as when the call was made
|
||||
* before any callback is invoked.
|
||||
* <p>
|
||||
* You should never rely on this class directly when using or extending Dubbo, the implementation of {@link AsyncRpcResult}
|
||||
* is only a workaround for compatibility purpose. It may be changed or even get removed from the next major version.
|
||||
* Please only use {@link Result} or {@link RpcResult}.
|
||||
*
|
||||
* Extending the {@link Filter} is one typical use case:
|
||||
* <pre>
|
||||
* {@code
|
||||
* public class YourFilter implements Filter {
|
||||
* @Override
|
||||
* public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
* System.out.println("Filter get the return value: " + result.getValue());
|
||||
* // Don't do this
|
||||
* // AsyncRpcResult asyncRpcResult = ((AsyncRpcResult)result;
|
||||
* // System.out.println("Filter get the return value: " + asyncRpcResult.getValue());
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
* return invoker.invoke(invocation);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </p>
|
||||
* TODO RpcResult can be an instance of {@link java.util.concurrent.CompletionStage} instead of composing CompletionStage inside.
|
||||
* TODO if it's reasonable or even right to keep a reference to Invocation?
|
||||
* <p>
|
||||
* As {@link Result} implements CompletionStage, {@link AsyncRpcResult} allows you to easily build a async filter chain whose status will be
|
||||
* driven entirely by the state of the underlying RPC call.
|
||||
* <p>
|
||||
* AsyncRpcResult does not contain any concrete value (except the underlying value bring by CompletableFuture), consider it as a status transfer node.
|
||||
* {@link #getValue()} and {@link #getException()} are all inherited from {@link Result} interface, implementing them are mainly
|
||||
* for compatibility consideration. Because many legacy {@link Filter} implementation are most possibly to call getValue directly.
|
||||
*/
|
||||
public class AsyncRpcResult extends AbstractResult {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AsyncRpcResult.class);
|
||||
|
||||
/**
|
||||
* RpcContext can be changed, because thread may have been used by other thread. It should be cloned before store.
|
||||
* So we use Invocation instead, Invocation will create for every invoke, but invocation only support attachments of string type.
|
||||
* RpcContext may already have been changed when callback happens, it happens when the same thread is used to execute another RPC call.
|
||||
* So we should keep the reference of current RpcContext instance and restore it before callback being executed.
|
||||
*/
|
||||
private RpcContext storedContext;
|
||||
private RpcContext storedServerContext;
|
||||
|
||||
protected CompletableFuture<Object> valueFuture;
|
||||
private Invocation invocation;
|
||||
|
||||
protected CompletableFuture<Result> resultFuture;
|
||||
|
||||
public AsyncRpcResult(CompletableFuture<Object> future) {
|
||||
this(future, true);
|
||||
public AsyncRpcResult(Invocation invocation) {
|
||||
this.invocation = invocation;
|
||||
this.storedContext = RpcContext.getContext();
|
||||
this.storedServerContext = RpcContext.getServerContext();
|
||||
}
|
||||
|
||||
public AsyncRpcResult(CompletableFuture<Object> future, boolean registerCallback) {
|
||||
this(future, new CompletableFuture<>(), registerCallback);
|
||||
public AsyncRpcResult(AsyncRpcResult asyncRpcResult) {
|
||||
this.invocation = asyncRpcResult.getInvocation();
|
||||
this.storedContext = asyncRpcResult.getStoredContext();
|
||||
this.storedServerContext = asyncRpcResult.getStoredServerContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param future
|
||||
* @param rFuture
|
||||
* @param registerCallback
|
||||
* Notice the return type of {@link #getValue} is the actual type of the RPC method, not {@link AppResponse}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AsyncRpcResult(CompletableFuture<Object> future, final CompletableFuture<Result> rFuture, boolean registerCallback) {
|
||||
if (rFuture == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
resultFuture = rFuture;
|
||||
if (registerCallback) {
|
||||
/**
|
||||
* We do not know whether future already completed or not, it's a future exposed or even created by end user.
|
||||
* 1. future complete before whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread subscribing, in our case, it's Dubbo thread.
|
||||
* 2. future complete after whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread calling complete, normally its User thread.
|
||||
*/
|
||||
future.whenComplete((v, t) -> {
|
||||
RpcResult rpcResult;
|
||||
if (t != null) {
|
||||
if (t instanceof CompletionException) {
|
||||
rpcResult = new RpcResult(t.getCause());
|
||||
} else {
|
||||
rpcResult = new RpcResult(t);
|
||||
}
|
||||
} else {
|
||||
rpcResult = new RpcResult(v);
|
||||
}
|
||||
// instead of resultFuture we must use rFuture here, resultFuture may being changed before complete when building filter chain, but rFuture was guaranteed never changed by closure.
|
||||
rFuture.complete(rpcResult);
|
||||
});
|
||||
}
|
||||
this.valueFuture = future;
|
||||
// employ copy of context avoid the other call may modify the context content
|
||||
this.storedContext = RpcContext.getContext().copyOf();
|
||||
this.storedServerContext = RpcContext.getServerContext().copyOf();
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return getAppResponse().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return getRpcResult().getValue();
|
||||
public void setValue(Object value) {
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setValue(value);
|
||||
this.complete(appResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return getRpcResult().getException();
|
||||
return getAppResponse().getException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setException(Throwable t) {
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setException(t);
|
||||
this.complete(appResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasException() {
|
||||
return getRpcResult().hasException();
|
||||
return getAppResponse().hasException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResult() {
|
||||
return getRpcResult().getResult();
|
||||
}
|
||||
|
||||
public CompletableFuture getValueFuture() {
|
||||
return valueFuture;
|
||||
}
|
||||
|
||||
public CompletableFuture<Result> getResultFuture() {
|
||||
return resultFuture;
|
||||
}
|
||||
|
||||
public void setResultFuture(CompletableFuture<Result> resultFuture) {
|
||||
this.resultFuture = resultFuture;
|
||||
}
|
||||
|
||||
public Result getRpcResult() {
|
||||
public Result getAppResponse() {
|
||||
try {
|
||||
if (resultFuture.isDone()) {
|
||||
return resultFuture.get();
|
||||
if (this.isDone()) {
|
||||
return this.get();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// This should never happen;
|
||||
logger.error("Got exception when trying to fetch the underlying result from AsyncRpcResult.", e);
|
||||
}
|
||||
return new RpcResult();
|
||||
return new AppResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object recreate() throws Throwable {
|
||||
return valueFuture;
|
||||
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
|
||||
if (InvokeMode.FUTURE == rpcInvocation.getInvokeMode()) {
|
||||
AppResponse appResponse = new AppResponse();
|
||||
CompletableFuture<Object> future = new CompletableFuture<>();
|
||||
appResponse.setValue(future);
|
||||
this.whenComplete((result, t) -> {
|
||||
if (t != null) {
|
||||
if (t instanceof CompletionException) {
|
||||
t = t.getCause();
|
||||
}
|
||||
future.completeExceptionally(t);
|
||||
} else {
|
||||
if (result.hasException()) {
|
||||
future.completeExceptionally(result.getException());
|
||||
} else {
|
||||
future.complete(result.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
return appResponse.recreate();
|
||||
} else if (this.isDone()) {
|
||||
return this.get().recreate();
|
||||
}
|
||||
return (new AppResponse()).recreate();
|
||||
}
|
||||
|
||||
public void thenApplyWithContext(Function<Result, Result> fn) {
|
||||
this.resultFuture = resultFuture.thenApply(fn.compose(beforeContext).andThen(afterContext));
|
||||
public Result thenApplyWithContext(Function<Result, Result> fn) {
|
||||
CompletableFuture<Result> future = this.thenApply(fn.compose(beforeContext).andThen(afterContext));
|
||||
AsyncRpcResult nextAsyncRpcResult = new AsyncRpcResult(this);
|
||||
nextAsyncRpcResult.subscribeTo(future);
|
||||
return nextAsyncRpcResult;
|
||||
}
|
||||
|
||||
public void subscribeTo(CompletableFuture<?> future) {
|
||||
future.whenComplete((obj, t) -> {
|
||||
if (t != null) {
|
||||
this.completeExceptionally(t);
|
||||
} else {
|
||||
this.complete((Result) obj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttachments() {
|
||||
return getRpcResult().getAttachments();
|
||||
return getAppResponse().getAttachments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachments(Map<String, String> map) {
|
||||
getRpcResult().setAttachments(map);
|
||||
getAppResponse().setAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAttachments(Map<String, String> map) {
|
||||
getRpcResult().addAttachments(map);
|
||||
getAppResponse().addAttachments(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key) {
|
||||
return getRpcResult().getAttachment(key);
|
||||
return getAppResponse().getAttachment(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachment(String key, String defaultValue) {
|
||||
return getRpcResult().getAttachment(key, defaultValue);
|
||||
return getAppResponse().getAttachment(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(String key, String value) {
|
||||
getRpcResult().setAttachment(key, value);
|
||||
getAppResponse().setAttachment(key, value);
|
||||
}
|
||||
|
||||
public RpcContext getStoredContext() {
|
||||
return storedContext;
|
||||
}
|
||||
|
||||
public RpcContext getStoredServerContext() {
|
||||
return storedServerContext;
|
||||
}
|
||||
|
||||
public Invocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -203,18 +201,51 @@ public class AsyncRpcResult extends AbstractResult {
|
|||
private RpcContext tmpContext;
|
||||
private RpcContext tmpServerContext;
|
||||
|
||||
private Function<Result, Result> beforeContext = (result) -> {
|
||||
private Function<Result, Result> beforeContext = (appResponse) -> {
|
||||
tmpContext = RpcContext.getContext();
|
||||
tmpServerContext = RpcContext.getServerContext();
|
||||
RpcContext.restoreContext(storedContext);
|
||||
RpcContext.restoreServerContext(storedServerContext);
|
||||
return result;
|
||||
return appResponse;
|
||||
};
|
||||
|
||||
private Function<Result, Result> afterContext = (result) -> {
|
||||
private Function<Result, Result> afterContext = (appResponse) -> {
|
||||
RpcContext.restoreContext(tmpContext);
|
||||
RpcContext.restoreServerContext(tmpServerContext);
|
||||
return result;
|
||||
return appResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* Some utility methods used to quickly generate default AsyncRpcResult instance.
|
||||
*/
|
||||
public static AsyncRpcResult newDefaultAsyncResult(AppResponse appResponse, Invocation invocation) {
|
||||
AsyncRpcResult asyncRpcResult = new AsyncRpcResult(invocation);
|
||||
asyncRpcResult.complete(appResponse);
|
||||
return asyncRpcResult;
|
||||
}
|
||||
|
||||
public static AsyncRpcResult newDefaultAsyncResult(Invocation invocation) {
|
||||
return newDefaultAsyncResult(null, null, invocation);
|
||||
}
|
||||
|
||||
public static AsyncRpcResult newDefaultAsyncResult(Object value, Invocation invocation) {
|
||||
return newDefaultAsyncResult(value, null, invocation);
|
||||
}
|
||||
|
||||
public static AsyncRpcResult newDefaultAsyncResult(Throwable t, Invocation invocation) {
|
||||
return newDefaultAsyncResult(null, t, invocation);
|
||||
}
|
||||
|
||||
public static AsyncRpcResult newDefaultAsyncResult(Object value, Throwable t, Invocation invocation) {
|
||||
AsyncRpcResult asyncRpcResult = new AsyncRpcResult(invocation);
|
||||
AppResponse appResponse = new AppResponse();
|
||||
if (t != null) {
|
||||
appResponse.setException(t);
|
||||
} else {
|
||||
appResponse.setValue(value);
|
||||
}
|
||||
asyncRpcResult.complete(appResponse);
|
||||
return asyncRpcResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,35 +42,29 @@ import org.apache.dubbo.common.extension.SPI;
|
|||
*/
|
||||
@SPI
|
||||
public interface Filter {
|
||||
|
||||
/**
|
||||
* do invoke filter.
|
||||
* <p>
|
||||
* <code>
|
||||
* // before filter
|
||||
* Result result = invoker.invoke(invocation);
|
||||
* // after filter
|
||||
* return result;
|
||||
* </code>
|
||||
*
|
||||
* @param invoker service
|
||||
* @param invocation invocation.
|
||||
* @return invoke result.
|
||||
* @throws RpcException
|
||||
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
|
||||
* Does not need to override/implement this method.
|
||||
*/
|
||||
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
|
||||
|
||||
/**
|
||||
* Return processing result
|
||||
* Filter itself should only be response for passing invocation, all callbacks has been placed into {@link Listener}
|
||||
*
|
||||
* @param result result
|
||||
* @param invoker invoker
|
||||
* @param invocation invocation
|
||||
* @return Return {@link Result}
|
||||
* @param appResponse
|
||||
* @param invoker
|
||||
* @param invocation
|
||||
* @return
|
||||
*/
|
||||
default Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
return result;
|
||||
@Deprecated
|
||||
default Result onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
return appResponse;
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
|
||||
void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);
|
||||
|
||||
void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 org.apache.dubbo.rpc;
|
||||
|
||||
import org.apache.dubbo.common.threadlocal.InternalThreadLocal;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Used for async call scenario. But if the method you are calling has a {@link CompletableFuture<?>} signature
|
||||
* you do not need to use this class since you will get a Future response directly.
|
||||
* <p>
|
||||
* Remember to save the Future reference before making another call using the same thread, otherwise,
|
||||
* the current Future will be override by the new one, which means you will lose the chance get the return value.
|
||||
*/
|
||||
public class FutureContext {
|
||||
|
||||
public static InternalThreadLocal<CompletableFuture<?>> futureTL = new InternalThreadLocal<>();
|
||||
|
||||
/**
|
||||
* get future.
|
||||
*
|
||||
* @param <T>
|
||||
* @return future
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> CompletableFuture<T> getCompletableFuture() {
|
||||
return (CompletableFuture<T>) futureTL.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* set future.
|
||||
*
|
||||
* @param future
|
||||
*/
|
||||
public static void setFuture(CompletableFuture<?> future) {
|
||||
futureTL.set(future);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -59,6 +59,10 @@ public interface Invocation {
|
|||
*/
|
||||
Map<String, String> getAttachments();
|
||||
|
||||
void setAttachment(String key, String value);
|
||||
|
||||
void setAttachmentIfAbsent(String key, String value);
|
||||
|
||||
/**
|
||||
* get attachment by key.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,12 +14,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc;
|
||||
|
||||
package com.alibaba.dubbo.remoting.exchange;
|
||||
public enum InvokeMode {
|
||||
|
||||
SYNC, ASYNC, FUTURE;
|
||||
|
||||
/**
|
||||
* 2019-04-18
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ResponseCallback extends org.apache.dubbo.remoting.exchange.ResponseCallback {
|
||||
}
|
||||
|
|
@ -14,16 +14,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.dubbo.rpc.protocol.dubbo;
|
||||
|
||||
import org.apache.dubbo.remoting.exchange.ResponseFuture;
|
||||
package org.apache.dubbo.rpc;
|
||||
|
||||
/**
|
||||
* 2019-04-18
|
||||
*
|
||||
*/
|
||||
public class FutureAdapter<V> extends org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter<V> {
|
||||
public FutureAdapter(ResponseFuture future) {
|
||||
super(future);
|
||||
public abstract class ListenableFilter implements Filter {
|
||||
|
||||
protected Listener listener = null;
|
||||
|
||||
public Listener listener() {
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,16 +18,27 @@ package org.apache.dubbo.rpc;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
/**
|
||||
* RPC invoke result. (API, Prototype, NonThreadSafe)
|
||||
* (API, Prototype, NonThreadSafe)
|
||||
*
|
||||
* An RPC {@link Result}.
|
||||
*
|
||||
* Known implementations are:
|
||||
* 1. {@link AsyncRpcResult}, it's a {@link CompletionStage} whose underlying value signifies the return value of an RPC call.
|
||||
* 2. {@link AppResponse}, it inevitably inherits {@link CompletionStage} and {@link Future}, but you should never treat AppResponse as a type of Future,
|
||||
* instead, it is a normal concrete type.
|
||||
*
|
||||
* @serial Don't change the class name and package name.
|
||||
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
|
||||
* @see org.apache.dubbo.rpc.RpcResult
|
||||
* @see AppResponse
|
||||
*/
|
||||
public interface Result extends Serializable {
|
||||
public interface Result extends CompletionStage<Result>, Future<Result>, Serializable {
|
||||
|
||||
/**
|
||||
* Get invoke result.
|
||||
|
|
@ -36,6 +47,8 @@ public interface Result extends Serializable {
|
|||
*/
|
||||
Object getValue();
|
||||
|
||||
void setValue(Object value);
|
||||
|
||||
/**
|
||||
* Get exception.
|
||||
*
|
||||
|
|
@ -43,6 +56,8 @@ public interface Result extends Serializable {
|
|||
*/
|
||||
Throwable getException();
|
||||
|
||||
void setException(Throwable t);
|
||||
|
||||
/**
|
||||
* Has exception.
|
||||
*
|
||||
|
|
@ -66,14 +81,6 @@ public interface Result extends Serializable {
|
|||
*/
|
||||
Object recreate() throws Throwable;
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.rpc.Result#getValue()
|
||||
* @deprecated Replace to getValue()
|
||||
*/
|
||||
@Deprecated
|
||||
Object getResult();
|
||||
|
||||
|
||||
/**
|
||||
* get attachments.
|
||||
*
|
||||
|
|
@ -111,4 +118,26 @@ public interface Result extends Serializable {
|
|||
|
||||
void setAttachment(String key, String value);
|
||||
|
||||
/**
|
||||
* Returns the specified {@code valueIfAbsent} when not complete, or
|
||||
* returns the result value or throws an exception when complete.
|
||||
*
|
||||
* @see CompletableFuture#getNow(Object)
|
||||
*/
|
||||
Result getNow(Result valueIfAbsent);
|
||||
|
||||
/**
|
||||
* Add a callback which can be triggered when the RPC call finishes.
|
||||
* <p>
|
||||
* Just as the method name implies, this method will guarantee the callback being triggered under the same context as when the call was started,
|
||||
* see implementation in {@link AsyncRpcResult#thenApplyWithContext(Function)}
|
||||
*
|
||||
* @param fn
|
||||
* @return
|
||||
*/
|
||||
Result thenApplyWithContext(Function<Result, Result> fn);
|
||||
|
||||
default CompletableFuture<Result> completionFuture() {
|
||||
return toCompletableFuture();
|
||||
}
|
||||
}
|
||||
|
|
@ -75,7 +75,6 @@ public class RpcContext {
|
|||
|
||||
private final Map<String, String> attachments = new HashMap<String, String>();
|
||||
private final Map<String, Object> values = new HashMap<String, Object>();
|
||||
private Future<?> future;
|
||||
|
||||
private List<URL> urls;
|
||||
|
||||
|
|
@ -144,32 +143,6 @@ public class RpcContext {
|
|||
LOCAL.set(oldContext);
|
||||
}
|
||||
|
||||
|
||||
public RpcContext copyOf() {
|
||||
RpcContext copy = new RpcContext();
|
||||
copy.attachments.putAll(this.attachments);
|
||||
copy.values.putAll(this.values);
|
||||
copy.future = this.future;
|
||||
copy.urls = this.urls;
|
||||
copy.url = this.url;
|
||||
copy.methodName = this.methodName;
|
||||
copy.parameterTypes = this.parameterTypes;
|
||||
copy.arguments = this.arguments;
|
||||
copy.localAddress = this.localAddress;
|
||||
copy.remoteAddress = this.remoteAddress;
|
||||
copy.remoteApplicationName = this.remoteApplicationName;
|
||||
copy.invokers = this.invokers;
|
||||
copy.invoker = this.invoker;
|
||||
copy.invocation = this.invocation;
|
||||
|
||||
copy.request = this.request;
|
||||
copy.response = this.response;
|
||||
copy.asyncContext = this.asyncContext;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* remove context.
|
||||
*
|
||||
|
|
@ -251,7 +224,7 @@ public class RpcContext {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> CompletableFuture<T> getCompletableFuture() {
|
||||
return (CompletableFuture<T>) future;
|
||||
return FutureContext.getCompletableFuture();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,7 +235,7 @@ public class RpcContext {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Future<T> getFuture() {
|
||||
return (Future<T>) future;
|
||||
return FutureContext.getCompletableFuture();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -270,8 +243,8 @@ public class RpcContext {
|
|||
*
|
||||
* @param future
|
||||
*/
|
||||
public void setFuture(Future<?> future) {
|
||||
this.future = future;
|
||||
public void setFuture(CompletableFuture<?> future) {
|
||||
FutureContext.setFuture(future);
|
||||
}
|
||||
|
||||
public List<URL> getUrls() {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
|
||||
private transient Invoker<?> invoker;
|
||||
|
||||
private transient Class<?> returnType;
|
||||
|
||||
private transient InvokeMode invokeMode;
|
||||
|
||||
public RpcInvocation() {
|
||||
}
|
||||
|
||||
|
|
@ -94,6 +98,7 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
|
||||
public RpcInvocation(Method method, Object[] arguments, Map<String, String> attachment) {
|
||||
this(method.getName(), method.getParameterTypes(), arguments, attachment, null);
|
||||
this.returnType = method.getReturnType();
|
||||
}
|
||||
|
||||
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) {
|
||||
|
|
@ -212,6 +217,22 @@ public class RpcInvocation implements Invocation, Serializable {
|
|||
return value;
|
||||
}
|
||||
|
||||
public Class<?> getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public void setReturnType(Class<?> returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
public InvokeMode getInvokeMode() {
|
||||
return invokeMode;
|
||||
}
|
||||
|
||||
public void setInvokeMode(InvokeMode invokeMode) {
|
||||
this.invokeMode = invokeMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RpcInvocation [methodName=" + methodName + ", parameterTypes="
|
||||
|
|
|
|||
|
|
@ -1,128 +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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* RPC Result.
|
||||
*
|
||||
* @serial Don't change the class name and properties.
|
||||
*/
|
||||
public class RpcResult extends AbstractResult {
|
||||
|
||||
private static final long serialVersionUID = -6925924956850004727L;
|
||||
|
||||
public RpcResult() {
|
||||
}
|
||||
|
||||
public RpcResult(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public RpcResult(Throwable exception) {
|
||||
this.exception = handleStackTraceNull(exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object recreate() throws Throwable {
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.rpc.RpcResult#getValue()
|
||||
* @deprecated Replace to getValue()
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public Object getResult() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.rpc.RpcResult#setValue(Object)
|
||||
* @deprecated Replace to setValue()
|
||||
*/
|
||||
@Deprecated
|
||||
public void setResult(Object result) {
|
||||
setValue(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.result = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public void setException(Throwable e) {
|
||||
this.exception = handleStackTraceNull(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasException() {
|
||||
return exception != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RpcResult [result=" + result + ", exception=" + exception + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* we need to deal the exception whose stack trace is null.
|
||||
* <p>
|
||||
* see https://github.com/apache/incubator-dubbo/pull/2956
|
||||
* and https://github.com/apache/incubator-dubbo/pull/3634
|
||||
* and https://github.com/apache/incubator-dubbo/issues/619
|
||||
*
|
||||
* @param e exception
|
||||
* @return exception after deal with stack trace
|
||||
*/
|
||||
private Throwable handleStackTraceNull(Throwable e) {
|
||||
if (e != null) {
|
||||
try {
|
||||
// get Throwable class
|
||||
Class clazz = e.getClass();
|
||||
while (!clazz.getName().equals(Throwable.class.getName())) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
// get stackTrace value
|
||||
Field stackTraceField = clazz.getDeclaredField("stackTrace");
|
||||
stackTraceField.setAccessible(true);
|
||||
Object stackTrace = stackTraceField.get(e);
|
||||
if (stackTrace == null) {
|
||||
e.setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +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;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* A sub class used for normal async invoke.
|
||||
*
|
||||
* <b>NOTICE!!</b>
|
||||
*
|
||||
* <p>
|
||||
* You should never rely on this class directly when using or extending Dubbo, the implementation of {@link SimpleAsyncRpcResult}
|
||||
* is only a workaround for compatibility purpose. It may be changed or even get removed from the next major version.
|
||||
* Please only use {@link Result} or {@link RpcResult}.
|
||||
* </p>
|
||||
*
|
||||
* Check {@link AsyncRpcResult} for more details.
|
||||
*
|
||||
* TODO AsyncRpcResult, AsyncNormalRpcResult should not be a parent-child hierarchy.
|
||||
*/
|
||||
public class SimpleAsyncRpcResult extends AsyncRpcResult {
|
||||
public SimpleAsyncRpcResult(CompletableFuture<Object> future, boolean registerCallback) {
|
||||
super(future, registerCallback);
|
||||
}
|
||||
|
||||
public SimpleAsyncRpcResult(CompletableFuture<Object> future, CompletableFuture<Result> rFuture, boolean registerCallback) {
|
||||
super(future, rFuture, registerCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object recreate() throws Throwable {
|
||||
// TODO should we check the status of valueFuture here?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,9 +18,11 @@ package org.apache.dubbo.rpc.filter;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcStatus;
|
||||
|
|
@ -42,50 +44,75 @@ import static org.apache.dubbo.rpc.Constants.ACTIVES_KEY;
|
|||
* @see Filter
|
||||
*/
|
||||
@Activate(group = CONSUMER, value = ACTIVES_KEY)
|
||||
public class ActiveLimitFilter implements Filter {
|
||||
public class ActiveLimitFilter extends ListenableFilter {
|
||||
|
||||
private static final String ACTIVELIMIT_FILTER_START_TIME = "activelimit_filter_start_time";
|
||||
|
||||
public ActiveLimitFilter() {
|
||||
super.listener = new ActiveLimitListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
URL url = invoker.getUrl();
|
||||
String methodName = invocation.getMethodName();
|
||||
int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0);
|
||||
RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
|
||||
RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
|
||||
if (!RpcStatus.beginCount(url, methodName, max)) {
|
||||
long timeout = invoker.getUrl().getMethodParameter(invocation.getMethodName(), TIMEOUT_KEY, 0);
|
||||
long start = System.currentTimeMillis();
|
||||
long remain = timeout;
|
||||
synchronized (count) {
|
||||
synchronized (rpcStatus) {
|
||||
while (!RpcStatus.beginCount(url, methodName, max)) {
|
||||
try {
|
||||
count.wait(remain);
|
||||
rpcStatus.wait(remain);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
remain = timeout - elapsed;
|
||||
if (remain <= 0) {
|
||||
throw new RpcException("Waiting concurrent invoke timeout in client-side for service: "
|
||||
+ invoker.getInterface().getName() + ", method: "
|
||||
+ invocation.getMethodName() + ", elapsed: " + elapsed
|
||||
+ ", timeout: " + timeout + ". concurrent invokes: " + count.getActive()
|
||||
+ ". max concurrent invoke limit: " + max);
|
||||
throw new RpcException("Waiting concurrent invoke timeout in client-side for service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", elapsed: " + elapsed + ", timeout: " + timeout + ". concurrent invokes: " + rpcStatus.getActive() + ". max concurrent invoke limit: " + max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSuccess = true;
|
||||
long begin = System.currentTimeMillis();
|
||||
try {
|
||||
return invoker.invoke(invocation);
|
||||
} catch (RuntimeException t) {
|
||||
isSuccess = false;
|
||||
throw t;
|
||||
} finally {
|
||||
RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isSuccess);
|
||||
invocation.setAttachment(ACTIVELIMIT_FILTER_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
static class ActiveLimitListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
String methodName = invocation.getMethodName();
|
||||
URL url = invoker.getUrl();
|
||||
int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0);
|
||||
|
||||
RpcStatus.endCount(url, methodName, getElapsed(invocation), true);
|
||||
notifyFinish(RpcStatus.getStatus(url, methodName), max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
String methodName = invocation.getMethodName();
|
||||
URL url = invoker.getUrl();
|
||||
int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 0);
|
||||
|
||||
RpcStatus.endCount(url, methodName, getElapsed(invocation), false);
|
||||
notifyFinish(RpcStatus.getStatus(url, methodName), max);
|
||||
}
|
||||
|
||||
private long getElapsed(Invocation invocation) {
|
||||
String beginTime = invocation.getAttachment(ACTIVELIMIT_FILTER_START_TIME);
|
||||
return StringUtils.isNotEmpty(beginTime) ? System.currentTimeMillis() - Long.parseLong(beginTime) : 0;
|
||||
}
|
||||
|
||||
private void notifyFinish(RpcStatus rpcStatus, int max) {
|
||||
if (max > 0) {
|
||||
synchronized (count) {
|
||||
count.notifyAll();
|
||||
synchronized (rpcStatus) {
|
||||
rpcStatus.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,17 +20,18 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.CompatibleTypeUtils;
|
||||
import org.apache.dubbo.common.utils.PojoUtils;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;
|
||||
|
||||
/**
|
||||
* CompatibleFilter make the remote method's return value compatible to invoker's version of object.
|
||||
* To make return object compatible it does
|
||||
|
|
@ -45,44 +46,54 @@ import java.lang.reflect.Type;
|
|||
* @see Filter
|
||||
*
|
||||
*/
|
||||
public class CompatibleFilter implements Filter {
|
||||
public class CompatibleFilter extends ListenableFilter {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(CompatibleFilter.class);
|
||||
|
||||
public CompatibleFilter() {
|
||||
super.listener = new CompatibleListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
Result result = invoker.invoke(invocation);
|
||||
if (!invocation.getMethodName().startsWith("$") && !result.hasException()) {
|
||||
Object value = result.getValue();
|
||||
if (value != null) {
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
Class<?> type = method.getReturnType();
|
||||
Object newValue;
|
||||
String serialization = invoker.getUrl().getParameter(Constants.SERIALIZATION_KEY);
|
||||
if ("json".equals(serialization)
|
||||
|| "fastjson".equals(serialization)) {
|
||||
// If the serialization key is json or fastjson
|
||||
Type gtype = method.getGenericReturnType();
|
||||
newValue = PojoUtils.realize(value, type, gtype);
|
||||
} else if (!type.isInstance(value)) {
|
||||
//if local service interface's method's return type is not instance of return value
|
||||
newValue = PojoUtils.isPojo(type)
|
||||
? PojoUtils.realize(value, type)
|
||||
: CompatibleTypeUtils.compatibleTypeConvert(value, type);
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
} else {
|
||||
newValue = value;
|
||||
static class CompatibleListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
if (!invocation.getMethodName().startsWith("$") && !appResponse.hasException()) {
|
||||
Object value = appResponse.getValue();
|
||||
if (value != null) {
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
Class<?> type = method.getReturnType();
|
||||
Object newValue;
|
||||
String serialization = invoker.getUrl().getParameter(SERIALIZATION_KEY);
|
||||
if ("json".equals(serialization) || "fastjson".equals(serialization)) {
|
||||
// If the serialization key is json or fastjson
|
||||
Type gtype = method.getGenericReturnType();
|
||||
newValue = PojoUtils.realize(value, type, gtype);
|
||||
} else if (!type.isInstance(value)) {
|
||||
//if local service interface's method's return type is not instance of return value
|
||||
newValue = PojoUtils.isPojo(type) ? PojoUtils.realize(value, type) : CompatibleTypeUtils.compatibleTypeConvert(value, type);
|
||||
|
||||
} else {
|
||||
newValue = value;
|
||||
}
|
||||
if (newValue != value) {
|
||||
appResponse.setValue(newValue);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
if (newValue != value) {
|
||||
result = new RpcResult(newValue);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,17 +16,18 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
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 static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||
|
||||
/**
|
||||
* ConsumerContextFilter set current RpcContext with invoker,invocation, local host, remote host and port
|
||||
* for consumer invoker.It does it to make the requires info available to execution thread's RpcContext.
|
||||
|
|
@ -34,8 +35,12 @@ import org.apache.dubbo.rpc.RpcInvocation;
|
|||
* @see org.apache.dubbo.rpc.Filter
|
||||
* @see RpcContext
|
||||
*/
|
||||
@Activate(group = CommonConstants.CONSUMER, order = -10000)
|
||||
public class ConsumerContextFilter implements Filter {
|
||||
@Activate(group = CONSUMER, order = -10000)
|
||||
public class ConsumerContextFilter extends ListenableFilter {
|
||||
|
||||
public ConsumerContextFilter() {
|
||||
super.listener = new ConsumerContextListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
|
|
@ -49,18 +54,22 @@ public class ConsumerContextFilter implements Filter {
|
|||
((RpcInvocation) invocation).setInvoker(invoker);
|
||||
}
|
||||
try {
|
||||
// TODO should we clear server context?
|
||||
RpcContext.removeServerContext();
|
||||
return invoker.invoke(invocation);
|
||||
} finally {
|
||||
// TODO removeContext? but we need to save future for RpcContext.getFuture() API. If clear attachments here, attachments will not available when postProcessResult is invoked.
|
||||
RpcContext.getContext().clearAttachments();
|
||||
RpcContext.removeContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
RpcContext.getServerContext().setAttachments(result.getAttachments());
|
||||
return result;
|
||||
static class ConsumerContextListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
RpcContext.getServerContext().setAttachments(appResponse.getAttachments());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
|
@ -48,9 +48,13 @@ import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
|||
* @see RpcContext
|
||||
*/
|
||||
@Activate(group = PROVIDER, order = -10000)
|
||||
public class ContextFilter implements Filter {
|
||||
public class ContextFilter extends ListenableFilter {
|
||||
private static final String TAG_KEY = "dubbo.tag";
|
||||
|
||||
public ContextFilter() {
|
||||
super.listener = new ContextListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
Map<String, String> attachments = invocation.getAttachments();
|
||||
|
|
@ -97,10 +101,16 @@ public class ContextFilter implements Filter {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
// pass attachments to result
|
||||
result.addAttachments(RpcContext.getServerContext().getAttachments());
|
||||
return result;
|
||||
static class ContextListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
// pass attachments to result
|
||||
appResponse.addAttachments(RpcContext.getServerContext().getAttachments());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ package org.apache.dubbo.rpc.filter;
|
|||
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.$ECHO;
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ public class EchoFilter implements Filter {
|
|||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
|
||||
if (inv.getMethodName().equals($ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) {
|
||||
return new RpcResult(inv.getArguments()[0]);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(inv.getArguments()[0], inv);
|
||||
}
|
||||
return invoker.invoke(inv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
|
@ -45,85 +44,82 @@ import java.lang.reflect.Method;
|
|||
* </ol>
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER)
|
||||
public class ExceptionFilter implements Filter {
|
||||
|
||||
private final Logger logger;
|
||||
public class ExceptionFilter extends ListenableFilter {
|
||||
|
||||
public ExceptionFilter() {
|
||||
this(LoggerFactory.getLogger(ExceptionFilter.class));
|
||||
}
|
||||
|
||||
public ExceptionFilter(Logger logger) {
|
||||
this.logger = logger;
|
||||
super.listener = new ExceptionListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
try {
|
||||
return invoker.invoke(invocation);
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
|
||||
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
|
||||
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
if (result.hasException() && GenericService.class != invoker.getInterface()) {
|
||||
try {
|
||||
Throwable exception = result.getException();
|
||||
static class ExceptionListener implements Listener {
|
||||
|
||||
// directly throw if it's checked exception
|
||||
if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
|
||||
return result;
|
||||
}
|
||||
// directly throw if the exception appears in the signature
|
||||
private Logger logger = LoggerFactory.getLogger(ExceptionListener.class);
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
Class<?>[] exceptionClassses = method.getExceptionTypes();
|
||||
for (Class<?> exceptionClass : exceptionClassses) {
|
||||
if (exception.getClass().equals(exceptionClass)) {
|
||||
return result;
|
||||
}
|
||||
Throwable exception = appResponse.getException();
|
||||
|
||||
// directly throw if it's checked exception
|
||||
if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
|
||||
return;
|
||||
}
|
||||
// directly throw if the exception appears in the signature
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
|
||||
Class<?>[] exceptionClassses = method.getExceptionTypes();
|
||||
for (Class<?> exceptionClass : exceptionClassses) {
|
||||
if (exception.getClass().equals(exceptionClass)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
return;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// for the exception not found in method's signature, print ERROR message in server's log.
|
||||
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
|
||||
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
|
||||
+ ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
|
||||
// for the exception not found in method's signature, print ERROR message in server's log.
|
||||
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
|
||||
|
||||
// directly throw if exception class and interface class are in the same jar file.
|
||||
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
|
||||
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
|
||||
if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
|
||||
return result;
|
||||
}
|
||||
// directly throw if it's JDK exception
|
||||
String className = exception.getClass().getName();
|
||||
if (className.startsWith("java.") || className.startsWith("javax.")) {
|
||||
return result;
|
||||
}
|
||||
// directly throw if it's dubbo exception
|
||||
if (exception instanceof RpcException) {
|
||||
return result;
|
||||
}
|
||||
// directly throw if exception class and interface class are in the same jar file.
|
||||
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
|
||||
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
|
||||
if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
|
||||
return;
|
||||
}
|
||||
// directly throw if it's JDK exception
|
||||
String className = exception.getClass().getName();
|
||||
if (className.startsWith("java.") || className.startsWith("javax.")) {
|
||||
return;
|
||||
}
|
||||
// directly throw if it's dubbo exception
|
||||
if (exception instanceof RpcException) {
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, wrap with RuntimeException and throw back to the client
|
||||
return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
|
||||
} catch (Throwable e) {
|
||||
logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()
|
||||
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
|
||||
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
|
||||
return result;
|
||||
// otherwise, wrap with RuntimeException and throw back to the client
|
||||
appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
|
||||
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// For test purpose
|
||||
public void setLogger(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ package org.apache.dubbo.rpc.filter;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcStatus;
|
||||
|
|
@ -30,12 +31,20 @@ import static org.apache.dubbo.rpc.Constants.EXECUTES_KEY;
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* The maximum parallel execution request count per method per service for the provider.If the max configured
|
||||
* <b>executes</b> is set to 10 and if invoke request where it is already 10 then it will throws exception. It
|
||||
* continue the same behaviour un till it is <10.
|
||||
*
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER, value = EXECUTES_KEY)
|
||||
public class ExecuteLimitFilter implements Filter {
|
||||
public class ExecuteLimitFilter extends ListenableFilter {
|
||||
|
||||
private static final String EXECUTELIMIT_FILTER_START_TIME = "execugtelimit_filter_start_time";
|
||||
|
||||
public ExecuteLimitFilter() {
|
||||
super.listener = new ExecuteLimitListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
|
|
@ -48,20 +57,32 @@ public class ExecuteLimitFilter implements Filter {
|
|||
"\" /> limited.");
|
||||
}
|
||||
|
||||
long begin = System.currentTimeMillis();
|
||||
boolean isSuccess = true;
|
||||
invocation.setAttachment(EXECUTELIMIT_FILTER_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
try {
|
||||
return invoker.invoke(invocation);
|
||||
} catch (Throwable t) {
|
||||
isSuccess = false;
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
} else {
|
||||
throw new RpcException("unexpected exception when ExecuteLimitFilter", t);
|
||||
}
|
||||
} finally {
|
||||
RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
static class ExecuteLimitListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
RpcStatus.endCount(invoker.getUrl(), invocation.getMethodName(), getElapsed(invocation), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
RpcStatus.endCount(invoker.getUrl(), invocation.getMethodName(), getElapsed(invocation), false);
|
||||
}
|
||||
|
||||
private long getElapsed(Invocation invocation) {
|
||||
String beginTime = invocation.getAttachment(EXECUTELIMIT_FILTER_START_TIME);
|
||||
return StringUtils.isNotEmpty(beginTime) ? System.currentTimeMillis() - Long.parseLong(beginTime) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,13 @@ import org.apache.dubbo.common.serialize.Serialization;
|
|||
import org.apache.dubbo.common.utils.PojoUtils;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
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.RpcResult;
|
||||
import org.apache.dubbo.rpc.service.GenericException;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.ProtocolUtils;
|
||||
|
|
@ -44,20 +43,25 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_NATIVE_JAVA;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_BEAN;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_PROTOBUF;
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE_ASYNC;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_BEAN;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_NATIVE_JAVA;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_PROTOBUF;
|
||||
|
||||
/**
|
||||
* GenericInvokerFilter.
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER, order = -20000)
|
||||
public class GenericFilter implements Filter {
|
||||
public class GenericFilter extends ListenableFilter {
|
||||
|
||||
public GenericFilter() {
|
||||
super.listener = new GenericListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
|
||||
if (inv.getMethodName().equals($INVOKE)
|
||||
if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
|
||||
&& inv.getArguments() != null
|
||||
&& inv.getArguments().length == 3
|
||||
&& !GenericService.class.isAssignableFrom(invoker.getInterface())) {
|
||||
|
|
@ -134,41 +138,7 @@ public class GenericFilter implements Filter {
|
|||
args[0].getClass().getName());
|
||||
}
|
||||
}
|
||||
Result result = invoker.invoke(new RpcInvocation(method, args, inv.getAttachments()));
|
||||
if (result.hasException()
|
||||
&& !(result.getException() instanceof GenericException)) {
|
||||
return new RpcResult(new GenericException(result.getException()));
|
||||
}
|
||||
if (ProtocolUtils.isJavaGenericSerialization(generic)) {
|
||||
try {
|
||||
UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
|
||||
ExtensionLoader.getExtensionLoader(Serialization.class)
|
||||
.getExtension(GENERIC_SERIALIZATION_NATIVE_JAVA)
|
||||
.serialize(null, os).writeObject(result.getValue());
|
||||
return new RpcResult(os.toByteArray());
|
||||
} catch (IOException e) {
|
||||
throw new RpcException(
|
||||
"Generic serialization [" +
|
||||
GENERIC_SERIALIZATION_NATIVE_JAVA +
|
||||
"] serialize result failed.", e);
|
||||
}
|
||||
} else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
|
||||
return new RpcResult(JavaBeanSerializeUtil.serialize(result.getValue(), JavaBeanAccessor.METHOD));
|
||||
} else if (ProtocolUtils.isProtobufGenericSerialization(generic)) {
|
||||
try {
|
||||
UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
|
||||
ExtensionLoader.getExtensionLoader(Serialization.class)
|
||||
.getExtension(GENERIC_SERIALIZATION_PROTOBUF)
|
||||
.serialize(null, os).writeObject(result.getValue());
|
||||
return new RpcResult(os.toString());
|
||||
} catch (IOException e) {
|
||||
throw new RpcException("Generic serialization [" +
|
||||
GENERIC_SERIALIZATION_PROTOBUF +
|
||||
"] serialize result failed.", e);
|
||||
}
|
||||
} else {
|
||||
return new RpcResult(PojoUtils.generalize(result.getValue()));
|
||||
}
|
||||
return invoker.invoke(new RpcInvocation(method, args, inv.getAttachments()));
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RpcException(e.getMessage(), e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
|
@ -178,4 +148,57 @@ public class GenericFilter implements Filter {
|
|||
return invoker.invoke(inv);
|
||||
}
|
||||
|
||||
static class GenericListener implements Listener {
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation inv) {
|
||||
if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
|
||||
&& inv.getArguments() != null
|
||||
&& inv.getArguments().length == 3
|
||||
&& !GenericService.class.isAssignableFrom(invoker.getInterface())) {
|
||||
|
||||
String generic = inv.getAttachment(GENERIC_KEY);
|
||||
if (StringUtils.isBlank(generic)) {
|
||||
generic = RpcContext.getContext().getAttachment(GENERIC_KEY);
|
||||
}
|
||||
|
||||
if (appResponse.hasException() && !(appResponse.getException() instanceof GenericException)) {
|
||||
appResponse.setException(new GenericException(appResponse.getException()));
|
||||
}
|
||||
if (ProtocolUtils.isJavaGenericSerialization(generic)) {
|
||||
try {
|
||||
UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
|
||||
ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(GENERIC_SERIALIZATION_NATIVE_JAVA).serialize(null, os).writeObject(appResponse.getValue());
|
||||
appResponse.setValue(os.toByteArray());
|
||||
} catch (IOException e) {
|
||||
throw new RpcException(
|
||||
"Generic serialization [" +
|
||||
GENERIC_SERIALIZATION_NATIVE_JAVA +
|
||||
"] serialize result failed.", e);
|
||||
}
|
||||
} else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
|
||||
appResponse.setValue(JavaBeanSerializeUtil.serialize(appResponse.getValue(), JavaBeanAccessor.METHOD));
|
||||
} else if (ProtocolUtils.isProtobufGenericSerialization(generic)) {
|
||||
try {
|
||||
UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
|
||||
ExtensionLoader.getExtensionLoader(Serialization.class)
|
||||
.getExtension(GENERIC_SERIALIZATION_PROTOBUF)
|
||||
.serialize(null, os).writeObject(appResponse.getValue());
|
||||
appResponse.setValue(os.toString());
|
||||
} catch (IOException e) {
|
||||
throw new RpcException("Generic serialization [" +
|
||||
GENERIC_SERIALIZATION_PROTOBUF +
|
||||
"] serialize result failed.", e);
|
||||
}
|
||||
} else {
|
||||
appResponse.setValue(PojoUtils.generalize(appResponse.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,40 +25,46 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.utils.PojoUtils;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.service.GenericException;
|
||||
import org.apache.dubbo.rpc.support.ProtocolUtils;
|
||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE;
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE_ASYNC;
|
||||
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
|
||||
|
||||
/**
|
||||
* GenericImplInvokerFilter
|
||||
*/
|
||||
@Activate(group = CommonConstants.CONSUMER, value = GENERIC_KEY, order = 20000)
|
||||
public class GenericImplFilter implements Filter {
|
||||
public class GenericImplFilter extends ListenableFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GenericImplFilter.class);
|
||||
|
||||
private static final Class<?>[] GENERIC_PARAMETER_TYPES = new Class<?>[]{String.class, String[].class, Object[].class};
|
||||
|
||||
public GenericImplFilter() {
|
||||
super.listener = new GenericImplListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
String generic = invoker.getUrl().getParameter(GENERIC_KEY);
|
||||
if (ProtocolUtils.isGeneric(generic)
|
||||
&& !$INVOKE.equals(invocation.getMethodName())
|
||||
&& (!$INVOKE.equals(invocation.getMethodName()) && !$INVOKE_ASYNC.equals(invocation.getMethodName()))
|
||||
&& invocation instanceof RpcInvocation) {
|
||||
RpcInvocation invocation2 = (RpcInvocation) invocation;
|
||||
RpcInvocation invocation2 = new RpcInvocation(invocation);
|
||||
String methodName = invocation2.getMethodName();
|
||||
Class<?>[] parameterTypes = invocation2.getParameterTypes();
|
||||
Object[] arguments = invocation2.getArguments();
|
||||
|
|
@ -78,77 +84,15 @@ public class GenericImplFilter implements Filter {
|
|||
args = PojoUtils.generalize(arguments);
|
||||
}
|
||||
|
||||
invocation2.setMethodName($INVOKE);
|
||||
if (RpcUtils.isReturnTypeFuture(invocation)) {
|
||||
invocation2.setMethodName($INVOKE_ASYNC);
|
||||
} else {
|
||||
invocation2.setMethodName($INVOKE);
|
||||
}
|
||||
invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES);
|
||||
invocation2.setArguments(new Object[]{methodName, types, args});
|
||||
Result result = invoker.invoke(invocation2);
|
||||
|
||||
if (!result.hasException()) {
|
||||
Object value = result.getValue();
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(methodName, parameterTypes);
|
||||
if (ProtocolUtils.isBeanGenericSerialization(generic)) {
|
||||
if (value == null) {
|
||||
return new RpcResult(value);
|
||||
} else if (value instanceof JavaBeanDescriptor) {
|
||||
return new RpcResult(JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) value));
|
||||
} else {
|
||||
throw new RpcException(
|
||||
"The type of result value is " +
|
||||
value.getClass().getName() +
|
||||
" other than " +
|
||||
JavaBeanDescriptor.class.getName() +
|
||||
", and the result is " +
|
||||
value);
|
||||
}
|
||||
} else {
|
||||
return new RpcResult(PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType()));
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RpcException(e.getMessage(), e);
|
||||
}
|
||||
} else if (result.getException() instanceof GenericException) {
|
||||
GenericException exception = (GenericException) result.getException();
|
||||
try {
|
||||
String className = exception.getExceptionClass();
|
||||
Class<?> clazz = ReflectUtils.forName(className);
|
||||
Throwable targetException = null;
|
||||
Throwable lastException = null;
|
||||
try {
|
||||
targetException = (Throwable) clazz.newInstance();
|
||||
} catch (Throwable e) {
|
||||
lastException = e;
|
||||
for (Constructor<?> constructor : clazz.getConstructors()) {
|
||||
try {
|
||||
targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]);
|
||||
break;
|
||||
} catch (Throwable e1) {
|
||||
lastException = e1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetException != null) {
|
||||
try {
|
||||
Field field = Throwable.class.getDeclaredField("detailMessage");
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
field.set(targetException, exception.getExceptionMessage());
|
||||
} catch (Throwable e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
result = new RpcResult(targetException);
|
||||
} else if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (invocation.getMethodName().equals($INVOKE)
|
||||
return invoker.invoke(invocation2);
|
||||
} else if ((invocation.getMethodName().equals($INVOKE) || invocation.getMethodName().equals($INVOKE_ASYNC))
|
||||
&& invocation.getArguments() != null
|
||||
&& invocation.getArguments().length == 3
|
||||
&& ProtocolUtils.isGeneric(generic)) {
|
||||
|
|
@ -169,19 +113,89 @@ public class GenericImplFilter implements Filter {
|
|||
}
|
||||
}
|
||||
|
||||
((RpcInvocation) invocation).setAttachment(GENERIC_KEY, invoker.getUrl().getParameter(GENERIC_KEY));
|
||||
invocation.setAttachment(
|
||||
GENERIC_KEY, invoker.getUrl().getParameter(GENERIC_KEY));
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
private void error(String generic, String expected, String actual) throws RpcException {
|
||||
throw new RpcException(
|
||||
"Generic serialization [" +
|
||||
generic +
|
||||
"] only support message type " +
|
||||
expected +
|
||||
" and your message type is " +
|
||||
actual);
|
||||
throw new RpcException("Generic serialization [" + generic + "] only support message type " + expected + " and your message type is " + actual);
|
||||
}
|
||||
|
||||
static class GenericImplListener implements Listener {
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
String generic = invoker.getUrl().getParameter(GENERIC_KEY);
|
||||
String methodName = invocation.getMethodName();
|
||||
Class<?>[] parameterTypes = invocation.getParameterTypes();
|
||||
if (ProtocolUtils.isGeneric(generic)
|
||||
&& (!$INVOKE.equals(invocation.getMethodName()) && !$INVOKE_ASYNC.equals(invocation.getMethodName()))
|
||||
&& invocation instanceof RpcInvocation) {
|
||||
if (!appResponse.hasException()) {
|
||||
Object value = appResponse.getValue();
|
||||
try {
|
||||
Method method = invoker.getInterface().getMethod(methodName, parameterTypes);
|
||||
if (ProtocolUtils.isBeanGenericSerialization(generic)) {
|
||||
if (value == null) {
|
||||
appResponse.setValue(value);
|
||||
} else if (value instanceof JavaBeanDescriptor) {
|
||||
appResponse.setValue(JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) value));
|
||||
} else {
|
||||
throw new RpcException("The type of result value is " + value.getClass().getName() + " other than " + JavaBeanDescriptor.class.getName() + ", and the result is " + value);
|
||||
}
|
||||
} else {
|
||||
Type[] types = ReflectUtils.getReturnTypes(method);
|
||||
appResponse.setValue(PojoUtils.realize(value, (Class<?>) types[0], types[1]));
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RpcException(e.getMessage(), e);
|
||||
}
|
||||
} else if (appResponse.getException() instanceof GenericException) {
|
||||
GenericException exception = (GenericException) appResponse.getException();
|
||||
try {
|
||||
String className = exception.getExceptionClass();
|
||||
Class<?> clazz = ReflectUtils.forName(className);
|
||||
Throwable targetException = null;
|
||||
Throwable lastException = null;
|
||||
try {
|
||||
targetException = (Throwable) clazz.newInstance();
|
||||
} catch (Throwable e) {
|
||||
lastException = e;
|
||||
for (Constructor<?> constructor : clazz.getConstructors()) {
|
||||
try {
|
||||
targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]);
|
||||
break;
|
||||
} catch (Throwable e1) {
|
||||
lastException = e1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetException != null) {
|
||||
try {
|
||||
Field field = Throwable.class.getDeclaredField("detailMessage");
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
field.set(targetException, exception.getExceptionMessage());
|
||||
} catch (Throwable e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
appResponse.setException(targetException);
|
||||
} else if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ import org.apache.dubbo.common.constants.CommonConstants;
|
|||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
|
@ -33,42 +32,40 @@ import java.util.Arrays;
|
|||
* Log any invocation timeout, but don't stop server from running
|
||||
*/
|
||||
@Activate(group = CommonConstants.PROVIDER)
|
||||
public class TimeoutFilter implements Filter {
|
||||
public class TimeoutFilter extends ListenableFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class);
|
||||
|
||||
private static final String TIMEOUT_FILTER_START_TIME = "timeout_filter_start_time";
|
||||
|
||||
@Override
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
if (invocation.getAttachments() != null) {
|
||||
long start = System.currentTimeMillis();
|
||||
invocation.getAttachments().put(TIMEOUT_FILTER_START_TIME, String.valueOf(start));
|
||||
} else {
|
||||
if (invocation instanceof RpcInvocation) {
|
||||
RpcInvocation invc = (RpcInvocation) invocation;
|
||||
long start = System.currentTimeMillis();
|
||||
invc.setAttachment(TIMEOUT_FILTER_START_TIME, String.valueOf(start));
|
||||
}
|
||||
}
|
||||
return invoker.invoke(invocation);
|
||||
public TimeoutFilter() {
|
||||
super.listener = new TimeoutListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
|
||||
String startAttach = invocation.getAttachment(TIMEOUT_FILTER_START_TIME);
|
||||
if (startAttach != null) {
|
||||
long elapsed = System.currentTimeMillis() - Long.valueOf(startAttach);
|
||||
if (invoker.getUrl() != null
|
||||
&& elapsed > invoker.getUrl().getMethodParameter(invocation.getMethodName(),
|
||||
"timeout", Integer.MAX_VALUE)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("invoke time out. method: " + invocation.getMethodName()
|
||||
+ " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is "
|
||||
+ invoker.getUrl() + ", invoke elapsed " + elapsed + " ms.");
|
||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||
invocation.setAttachment(TIMEOUT_FILTER_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
return invoker.invoke(invocation);
|
||||
}
|
||||
|
||||
static class TimeoutListener implements Listener {
|
||||
|
||||
@Override
|
||||
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
|
||||
String startAttach = invocation.getAttachment(TIMEOUT_FILTER_START_TIME);
|
||||
if (startAttach != null) {
|
||||
long elapsed = System.currentTimeMillis() - Long.valueOf(startAttach);
|
||||
if (invoker.getUrl() != null && elapsed > invoker.getUrl().getMethodParameter(invocation.getMethodName(), "timeout", Integer.MAX_VALUE)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("invoke time out. method: " + invocation.getMethodName() + " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is " + invoker.getUrl() + ", invoke elapsed " + elapsed + " ms.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@ import org.apache.dubbo.common.logger.LoggerFactory;
|
|||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
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.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
|
@ -38,8 +38,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
|
||||
/**
|
||||
* AbstractInvoker.
|
||||
*/
|
||||
|
|
@ -149,9 +147,8 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
*/
|
||||
invocation.addAttachments(contextAttachments);
|
||||
}
|
||||
if (getUrl().getMethodParameter(invocation.getMethodName(), ASYNC_KEY, false)) {
|
||||
invocation.setAttachment(ASYNC_KEY, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
|
||||
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
|
||||
|
||||
try {
|
||||
|
|
@ -159,21 +156,21 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
|
|||
} catch (InvocationTargetException e) { // biz exception
|
||||
Throwable te = e.getTargetException();
|
||||
if (te == null) {
|
||||
return new RpcResult(e);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
} else {
|
||||
if (te instanceof RpcException) {
|
||||
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
|
||||
}
|
||||
return new RpcResult(te);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
if (e.isBiz()) {
|
||||
return new RpcResult(e);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
return new RpcResult(e);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.apache.dubbo.remoting.Constants;
|
|||
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.support.ProtocolUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -84,4 +85,11 @@ public abstract class AbstractProtocol implements Protocol {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
|
||||
return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
|
||||
}
|
||||
|
||||
protected abstract <T> Invoker<T> protocolBindingRefer(Class<T> type, URL url) throws RpcException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,13 +95,14 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> Invoker<T> refer(final Class<T> type, final URL url) throws RpcException {
|
||||
protected <T> Invoker<T> protocolBindingRefer(final Class<T> type, final URL url) throws RpcException {
|
||||
final Invoker<T> target = proxyFactory.getInvoker(doRefer(type, url), type, url);
|
||||
Invoker<T> invoker = new AbstractInvoker<T>(type, url) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) throws Throwable {
|
||||
try {
|
||||
Result result = target.invoke(invocation);
|
||||
// FIXME result is an AsyncRpcResult instance.
|
||||
Throwable e = result.getException();
|
||||
if (e != null) {
|
||||
for (Class<?> rpcException : rpcExceptions) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
import org.apache.dubbo.remoting.TimeoutException;
|
||||
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.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* This class will work as a wrapper wrapping outside of each protocol invoker.
|
||||
* @param <T>
|
||||
*/
|
||||
public class AsyncToSyncInvoker<T> implements Invoker<T> {
|
||||
|
||||
private Invoker<T> invoker;
|
||||
|
||||
public AsyncToSyncInvoker(Invoker<T> invoker) {
|
||||
this.invoker = invoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getInterface() {
|
||||
return invoker.getInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
Result asyncResult = invoker.invoke(invocation);
|
||||
|
||||
try {
|
||||
if (InvokeMode.SYNC == ((RpcInvocation)invocation).getInvokeMode()) {
|
||||
asyncResult.get();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RpcException("Interrupted unexpectedly while waiting for remoting result to return! method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof TimeoutException) {
|
||||
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
} else if (t instanceof RemotingException) {
|
||||
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException(e.getMessage(), e);
|
||||
}
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() {
|
||||
return invoker.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return invoker.isAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
invoker.destroy();
|
||||
}
|
||||
|
||||
public Invoker<T> getInvoker() {
|
||||
return invoker;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,11 +19,11 @@ package org.apache.dubbo.rpc.protocol;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ListenableFilter;
|
||||
import org.apache.dubbo.rpc.Protocol;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
|
@ -75,14 +75,31 @@ public class ProtocolFilterWrapper implements Protocol {
|
|||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
Result result = filter.invoke(next, invocation);
|
||||
if (result instanceof AsyncRpcResult) {
|
||||
AsyncRpcResult asyncResult = (AsyncRpcResult) result;
|
||||
asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation));
|
||||
return asyncResult;
|
||||
} else {
|
||||
return filter.onResponse(result, invoker, invocation);
|
||||
Result asyncResult;
|
||||
try {
|
||||
asyncResult = filter.invoke(next, invocation);
|
||||
} catch (Exception e) {
|
||||
// onError callback
|
||||
if (filter instanceof ListenableFilter) {
|
||||
Filter.Listener listener = ((ListenableFilter) filter).listener();
|
||||
if (listener != null) {
|
||||
listener.onError(e, invoker, invocation);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return asyncResult.thenApplyWithContext(r -> {
|
||||
// onResponse callback
|
||||
if (filter instanceof ListenableFilter) {
|
||||
Filter.Listener listener = ((ListenableFilter) filter).listener();
|
||||
if (listener != null) {
|
||||
listener.onResponse(r, invoker, invocation);
|
||||
}
|
||||
} else {
|
||||
filter.onResponse(r, invoker, invocation);
|
||||
}
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.proxy;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncContextImpl;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
|
@ -26,11 +27,11 @@ 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.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
/**
|
||||
* InvokerWrapper
|
||||
|
|
@ -78,30 +79,48 @@ public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
|
|||
public void destroy() {
|
||||
}
|
||||
|
||||
// TODO Unified to AsyncResult?
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
RpcContext rpcContext = RpcContext.getContext();
|
||||
try {
|
||||
Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
|
||||
if (RpcUtils.isReturnTypeFuture(invocation)) {
|
||||
return new AsyncRpcResult((CompletableFuture<Object>) obj);
|
||||
} else if (rpcContext.isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back.
|
||||
return new AsyncRpcResult(((AsyncContextImpl)(rpcContext.getAsyncContext())).getInternalFuture());
|
||||
} else {
|
||||
return new RpcResult(obj);
|
||||
}
|
||||
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
|
||||
CompletableFuture<Object> future = wrapWithFuture(value, invocation);
|
||||
AsyncRpcResult asyncRpcResult = new AsyncRpcResult(invocation);
|
||||
future.whenComplete((obj, t) -> {
|
||||
AppResponse result = new AppResponse();
|
||||
if (t != null) {
|
||||
if (t instanceof CompletionException) {
|
||||
result.setException(t.getCause());
|
||||
} else {
|
||||
result.setException(t);
|
||||
}
|
||||
} else {
|
||||
result.setValue(obj);
|
||||
}
|
||||
asyncRpcResult.complete(result);
|
||||
});
|
||||
return asyncRpcResult;
|
||||
} catch (InvocationTargetException e) {
|
||||
// TODO async throw exception before async thread write back, should stop asyncContext
|
||||
if (rpcContext.isAsyncStarted() && !rpcContext.stopAsync()) {
|
||||
if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {
|
||||
logger.error("Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.", e);
|
||||
}
|
||||
return new RpcResult(e.getTargetException());
|
||||
return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);
|
||||
} catch (Throwable e) {
|
||||
throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Object> wrapWithFuture (Object value, Invocation invocation) {
|
||||
if (RpcContext.getContext().isAsyncStarted()) {
|
||||
return ((AsyncContextImpl)(RpcContext.getContext().getAsyncContext())).getInternalFuture();
|
||||
} else if (RpcUtils.isReturnTypeFuture(invocation)) {
|
||||
if (value == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return (CompletableFuture<Object>) value;
|
||||
}
|
||||
return CompletableFuture.completedFuture(value);
|
||||
}
|
||||
|
||||
protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,14 +20,10 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.FUTURE_RETURNTYPE_KEY;
|
||||
|
||||
/**
|
||||
* InvokerHandler
|
||||
*/
|
||||
|
|
@ -56,16 +52,6 @@ public class InvokerInvocationHandler implements InvocationHandler {
|
|||
return invoker.equals(args[0]);
|
||||
}
|
||||
|
||||
return invoker.invoke(createInvocation(method, args)).recreate();
|
||||
return invoker.invoke(new RpcInvocation(method, args)).recreate();
|
||||
}
|
||||
|
||||
private RpcInvocation createInvocation(Method method, Object[] args) {
|
||||
RpcInvocation invocation = new RpcInvocation(method, args);
|
||||
if (RpcUtils.hasFutureReturnType(method)) {
|
||||
invocation.setAttachment(FUTURE_RETURNTYPE_KEY, "true");
|
||||
invocation.setAttachment(ASYNC_KEY, "true");
|
||||
}
|
||||
return invocation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.service;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Generic service interface
|
||||
*
|
||||
|
|
@ -35,4 +37,12 @@ public interface GenericService {
|
|||
*/
|
||||
Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException;
|
||||
|
||||
default CompletableFuture<Object> $invokeAsync(String method, String[] parameterTypes, Object[] args) throws GenericException {
|
||||
Object object = $invoke(method, parameterTypes, args);
|
||||
if (object instanceof CompletableFuture) {
|
||||
return (CompletableFuture<Object>) object;
|
||||
}
|
||||
return CompletableFuture.completedFuture(object);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,18 +18,18 @@ package org.apache.dubbo.rpc.support;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.PojoUtils;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ final public class MockInvoker<T> implements Invoker<T> {
|
|||
try {
|
||||
Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
|
||||
Object value = parseMockValue(mock, returnTypes);
|
||||
return new RpcResult(value);
|
||||
return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
|
||||
} catch (Exception ew) {
|
||||
throw new RpcException("mock return invoke error. method :" + invocation.getMethodName()
|
||||
+ ", mock:" + mock + ", url: " + url, ew);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ final public class MockProtocol extends AbstractProtocol {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
|
||||
public <T> Invoker<T> protocolBindingRefer(Class<T> type, URL url) throws RpcException {
|
||||
return new MockInvoker<>(url, type);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,23 +22,22 @@ import org.apache.dubbo.common.logger.LoggerFactory;
|
|||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.InvokeMode;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE;
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.ID_KEY;
|
||||
import static org.apache.dubbo.common.constants.RpcConstants.$INVOKE_ASYNC;
|
||||
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.FUTURE_GENERATED_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.FUTURE_RETURNTYPE_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.ID_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
|
||||
/**
|
||||
* RpcUtils
|
||||
|
|
@ -71,7 +70,6 @@ public class RpcUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
// TODO why not get return type when initialize Invocation?
|
||||
public static Type[] getReturnTypes(Invocation invocation) {
|
||||
try {
|
||||
if (invocation != null && invocation.getInvoker() != null
|
||||
|
|
@ -86,24 +84,7 @@ public class RpcUtils {
|
|||
if (method.getReturnType() == void.class) {
|
||||
return null;
|
||||
}
|
||||
Class<?> returnType = method.getReturnType();
|
||||
Type genericReturnType = method.getGenericReturnType();
|
||||
if (Future.class.isAssignableFrom(returnType)) {
|
||||
if (genericReturnType instanceof ParameterizedType) {
|
||||
Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
|
||||
if (actualArgType instanceof ParameterizedType) {
|
||||
returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
|
||||
genericReturnType = actualArgType;
|
||||
} else {
|
||||
returnType = (Class<?>) actualArgType;
|
||||
genericReturnType = returnType;
|
||||
}
|
||||
} else {
|
||||
returnType = null;
|
||||
genericReturnType = null;
|
||||
}
|
||||
}
|
||||
return new Type[]{returnType, genericReturnType};
|
||||
return ReflectUtils.getReturnTypes(method);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
|
|
@ -190,11 +171,22 @@ public class RpcUtils {
|
|||
}
|
||||
|
||||
public static boolean isReturnTypeFuture(Invocation inv) {
|
||||
return Boolean.TRUE.toString().equals(inv.getAttachment(FUTURE_RETURNTYPE_KEY));
|
||||
Class<?> clazz = getReturnType(inv);
|
||||
return (clazz != null && CompletableFuture.class.isAssignableFrom(clazz)) || isGenericAsync(inv);
|
||||
}
|
||||
|
||||
public static boolean hasFutureReturnType(Method method) {
|
||||
return CompletableFuture.class.isAssignableFrom(method.getReturnType());
|
||||
public static InvokeMode getInvokeMode(URL url, Invocation inv) {
|
||||
if (isReturnTypeFuture(inv)) {
|
||||
return InvokeMode.FUTURE;
|
||||
} else if (isAsync(url, inv)) {
|
||||
return InvokeMode.ASYNC;
|
||||
} else {
|
||||
return InvokeMode.SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGenericAsync(Invocation inv) {
|
||||
return $INVOKE_ASYNC.equals(inv.getMethodName());
|
||||
}
|
||||
|
||||
public static boolean isOneway(URL url, Invocation inv) {
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ package org.apache.dubbo.rpc;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class RpcResultTest {
|
||||
public class AppResponseTest {
|
||||
@Test
|
||||
public void testRpcResultWithNormalException() {
|
||||
public void testAppResponseWithNormalException() {
|
||||
NullPointerException npe = new NullPointerException();
|
||||
RpcResult rpcResult = new RpcResult(npe);
|
||||
AppResponse appResponse = new AppResponse(npe);
|
||||
|
||||
StackTraceElement[] stackTrace = rpcResult.getException().getStackTrace();
|
||||
StackTraceElement[] stackTrace = appResponse.getException().getStackTrace();
|
||||
Assertions.assertNotNull(stackTrace);
|
||||
Assertions.assertTrue(stackTrace.length > 1);
|
||||
}
|
||||
|
|
@ -35,14 +35,14 @@ public class RpcResultTest {
|
|||
* please run this test in Run mode
|
||||
*/
|
||||
@Test
|
||||
public void testRpcResultWithEmptyStackTraceException() {
|
||||
public void testAppResponseWithEmptyStackTraceException() {
|
||||
Throwable throwable = buildEmptyStackTraceException();
|
||||
if (throwable == null) {
|
||||
return;
|
||||
}
|
||||
RpcResult rpcResult = new RpcResult(throwable);
|
||||
AppResponse appResponse = new AppResponse(throwable);
|
||||
|
||||
StackTraceElement[] stackTrace = rpcResult.getException().getStackTrace();
|
||||
StackTraceElement[] stackTrace = appResponse.getException().getStackTrace();
|
||||
Assertions.assertNotNull(stackTrace);
|
||||
Assertions.assertTrue(stackTrace.length == 0);
|
||||
}
|
||||
|
|
@ -50,10 +50,10 @@ public class RpcResultTest {
|
|||
@Test
|
||||
public void testSetExceptionWithNormalException() {
|
||||
NullPointerException npe = new NullPointerException();
|
||||
RpcResult rpcResult = new RpcResult();
|
||||
rpcResult.setException(npe);
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setException(npe);
|
||||
|
||||
StackTraceElement[] stackTrace = rpcResult.getException().getStackTrace();
|
||||
StackTraceElement[] stackTrace = appResponse.getException().getStackTrace();
|
||||
Assertions.assertNotNull(stackTrace);
|
||||
Assertions.assertTrue(stackTrace.length > 1);
|
||||
}
|
||||
|
|
@ -67,10 +67,10 @@ public class RpcResultTest {
|
|||
if (throwable == null) {
|
||||
return;
|
||||
}
|
||||
RpcResult rpcResult = new RpcResult();
|
||||
rpcResult.setException(throwable);
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setException(throwable);
|
||||
|
||||
StackTraceElement[] stackTrace = rpcResult.getException().getStackTrace();
|
||||
StackTraceElement[] stackTrace = appResponse.getException().getStackTrace();
|
||||
Assertions.assertNotNull(stackTrace);
|
||||
Assertions.assertTrue(stackTrace.length == 0);
|
||||
}
|
||||
|
|
@ -17,9 +17,9 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcStatus;
|
||||
import org.apache.dubbo.rpc.support.BlockMyInvoker;
|
||||
|
|
@ -35,13 +35,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* ActiveLimitFilterTest.java
|
||||
*/
|
||||
public class ActiveLimitFilterTest {
|
||||
|
||||
Filter activeLimitFilter = new ActiveLimitFilter();
|
||||
ActiveLimitFilter activeLimitFilter = new ActiveLimitFilter();
|
||||
|
||||
@Test
|
||||
public void testInvokeNoActives() {
|
||||
|
|
@ -97,7 +98,7 @@ public class ActiveLimitFilterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeTimeOut() {
|
||||
public void testInvokeTimeOut() throws Exception {
|
||||
int totalThread = 100;
|
||||
int maxActives = 10;
|
||||
long timeout = 1;
|
||||
|
|
@ -120,9 +121,14 @@ public class ActiveLimitFilterTest {
|
|||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
activeLimitFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = activeLimitFilter.invoke(invoker, invocation);
|
||||
Result result = asyncResult.get();
|
||||
activeLimitFilter.listener().onResponse(result, invoker, invocation);
|
||||
} catch (RpcException expected) {
|
||||
count.incrementAndGet();
|
||||
// activeLimitFilter.listener().onError(expected, invoker, invocation);
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
} finally {
|
||||
latchBlocking.countDown();
|
||||
|
|
@ -142,7 +148,7 @@ public class ActiveLimitFilterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeNotTimeOut() {
|
||||
public void testInvokeNotTimeOut() throws Exception {
|
||||
int totalThread = 100;
|
||||
int maxActives = 10;
|
||||
long timeout = 1000;
|
||||
|
|
@ -163,9 +169,14 @@ public class ActiveLimitFilterTest {
|
|||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
activeLimitFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = activeLimitFilter.invoke(invoker, invocation);
|
||||
Result result = asyncResult.get();
|
||||
activeLimitFilter.listener().onResponse(result, invoker, invocation);
|
||||
} catch (RpcException expected) {
|
||||
count.incrementAndGet();
|
||||
activeLimitFilter.listener().onError(expected, invoker, invocation);
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
} finally {
|
||||
latchBlocking.countDown();
|
||||
|
|
@ -208,6 +219,7 @@ public class ActiveLimitFilterTest {
|
|||
try {
|
||||
activeLimitFilter.invoke(invoker, invocation);
|
||||
} catch (RuntimeException ex) {
|
||||
activeLimitFilter.listener().onError(ex, invoker, invocation);
|
||||
int afterExceptionActiveCount = count.getActive();
|
||||
assertEquals(beforeExceptionActiveCount, afterExceptionActiveCount, "After exception active count should be same");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.Type;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
|
@ -37,7 +38,7 @@ import static org.mockito.Mockito.mock;
|
|||
* CompatibleFilterTest.java
|
||||
*/
|
||||
public class CompatibleFilterFilterTest {
|
||||
private Filter compatibleFilter = new CompatibleFilter();
|
||||
private CompatibleFilter compatibleFilter = new CompatibleFilter();
|
||||
private Invocation invocation;
|
||||
private Invoker invoker;
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
@ -76,7 +77,7 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setException(new RuntimeException());
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
|
|
@ -88,7 +89,7 @@ public class CompatibleFilterFilterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInvokerJsonPojoSerialization() {
|
||||
public void testInvokerJsonPojoSerialization() throws Exception {
|
||||
invocation = mock(Invocation.class);
|
||||
given(invocation.getMethodName()).willReturn("enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Type[].class});
|
||||
|
|
@ -97,18 +98,20 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(result, invocation));
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1&serialization=json");
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
Result filterResult = compatibleFilter.invoke(invoker, invocation);
|
||||
assertEquals(Type.High, filterResult.getValue());
|
||||
Result asyncResult = compatibleFilter.invoke(invoker, invocation);
|
||||
AppResponse appResponse = (AppResponse) asyncResult.get();
|
||||
compatibleFilter.listener().onResponse(appResponse, invoker, invocation);
|
||||
assertEquals(Type.High, appResponse.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokerNonJsonEnumSerialization() {
|
||||
public void testInvokerNonJsonEnumSerialization() throws Exception {
|
||||
invocation = mock(Invocation.class);
|
||||
given(invocation.getMethodName()).willReturn("enumlength");
|
||||
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{Type[].class});
|
||||
|
|
@ -117,14 +120,16 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(result, invocation));
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
given(invoker.getUrl()).willReturn(url);
|
||||
|
||||
Result filterResult = compatibleFilter.invoke(invoker, invocation);
|
||||
assertEquals(Type.High, filterResult.getValue());
|
||||
Result asyncResult = compatibleFilter.invoke(invoker, invocation);
|
||||
AppResponse appResponse = (AppResponse) asyncResult.get();
|
||||
compatibleFilter.listener().onResponse(appResponse, invoker, invocation);
|
||||
assertEquals(Type.High, appResponse.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -137,7 +142,7 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue(new String[]{"High"});
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
@ -157,7 +162,7 @@ public class CompatibleFilterFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("hello");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.NetUtils;
|
|||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.MockInvocation;
|
||||
|
|
@ -41,11 +42,13 @@ public class ConsumerContextFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
Invoker<DemoService> invoker = new MyInvoker<DemoService>(url);
|
||||
Invocation invocation = new MockInvocation();
|
||||
consumerContextFilter.invoke(invoker, invocation);
|
||||
assertEquals(invoker, RpcContext.getContext().getInvoker());
|
||||
assertEquals(invocation, RpcContext.getContext().getInvocation());
|
||||
assertEquals(NetUtils.getLocalHost() + ":0", RpcContext.getContext().getLocalAddressString());
|
||||
assertEquals("test:11", RpcContext.getContext().getRemoteAddressString());
|
||||
|
||||
Result asyncResult = consumerContextFilter.invoke(invoker, invocation);
|
||||
asyncResult.thenApplyWithContext(result -> {
|
||||
assertEquals(invoker, RpcContext.getContext().getInvoker());
|
||||
assertEquals(invocation, RpcContext.getContext().getInvocation());
|
||||
assertEquals(NetUtils.getLocalHost() + ":0", RpcContext.getContext().getLocalAddressString());
|
||||
assertEquals("test:11", RpcContext.getContext().getRemoteAddressString());
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -17,12 +17,12 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.MockInvocation;
|
||||
import org.apache.dubbo.rpc.support.MyInvoker;
|
||||
|
|
@ -55,7 +55,7 @@ public class ContextFilterTest {
|
|||
invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -46,7 +46,7 @@ public class EchoFilterTest {
|
|||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
@ -68,7 +68,7 @@ public class EchoFilterTest {
|
|||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
given(invoker.isAvailable()).willReturn(true);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
result.setValue("High");
|
||||
given(invoker.invoke(invocation)).willReturn(result);
|
||||
URL url = URL.valueOf("test://test:11/test?group=dubbo&version=1.1");
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
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.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.LocalException;
|
||||
|
||||
|
|
@ -51,18 +51,20 @@ public class ExceptionFilterTest {
|
|||
RpcContext.getContext().setRemoteAddress("127.0.0.1", 1234);
|
||||
RpcException exception = new RpcException("TestRpcException");
|
||||
|
||||
ExceptionFilter exceptionFilter = new ExceptionFilter(logger);
|
||||
ExceptionFilter exceptionFilter = new ExceptionFilter();
|
||||
RpcInvocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"world"});
|
||||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
given(invoker.getInterface()).willReturn(DemoService.class);
|
||||
given(invoker.invoke(eq(invocation))).willThrow(exception);
|
||||
|
||||
|
||||
try {
|
||||
exceptionFilter.invoke(invoker, invocation);
|
||||
} catch (RpcException e) {
|
||||
assertEquals("TestRpcException", e.getMessage());
|
||||
((ExceptionFilter.ExceptionListener) exceptionFilter.listener()).setLogger(logger);
|
||||
exceptionFilter.listener().onError(e, invoker, invocation);
|
||||
}
|
||||
|
||||
Mockito.verify(logger).error(eq("Got unchecked and undeclared exception which called by 127.0.0.1. service: "
|
||||
+ DemoService.class.getName() + ", method: sayHello, exception: "
|
||||
+ RpcException.class.getName() + ": TestRpcException"), eq(exception));
|
||||
|
|
@ -76,16 +78,16 @@ public class ExceptionFilterTest {
|
|||
ExceptionFilter exceptionFilter = new ExceptionFilter();
|
||||
RpcInvocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"world"});
|
||||
|
||||
RpcResult rpcResult = new RpcResult();
|
||||
rpcResult.setException(new IllegalArgumentException("java"));
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setException(new IllegalArgumentException("java"));
|
||||
|
||||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
when(invoker.invoke(invocation)).thenReturn(rpcResult);
|
||||
when(invoker.invoke(invocation)).thenReturn(appResponse);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result newResult = exceptionFilter.invoke(invoker, invocation);
|
||||
|
||||
Assertions.assertEquals(rpcResult.getException(), newResult.getException());
|
||||
Assertions.assertEquals(appResponse.getException(), newResult.getException());
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -96,42 +98,43 @@ public class ExceptionFilterTest {
|
|||
ExceptionFilter exceptionFilter = new ExceptionFilter();
|
||||
RpcInvocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"world"});
|
||||
|
||||
RpcResult rpcResult = new RpcResult();
|
||||
rpcResult.setException(new LocalException("localException"));
|
||||
AppResponse appResponse = new AppResponse();
|
||||
appResponse.setException(new LocalException("localException"));
|
||||
|
||||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
when(invoker.invoke(invocation)).thenReturn(rpcResult);
|
||||
when(invoker.invoke(invocation)).thenReturn(appResponse);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result newResult = exceptionFilter.invoke(invoker, invocation);
|
||||
|
||||
Assertions.assertEquals(rpcResult.getException(), newResult.getException());
|
||||
Assertions.assertEquals(appResponse.getException(), newResult.getException());
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testConvertToRunTimeException() {
|
||||
public void testConvertToRunTimeException() throws Exception {
|
||||
|
||||
ExceptionFilter exceptionFilter = new ExceptionFilter();
|
||||
RpcInvocation invocation = new RpcInvocation("sayHello", new Class<?>[]{String.class}, new Object[]{"world"});
|
||||
|
||||
RpcResult rpcResult = new RpcResult();
|
||||
rpcResult.setException(new HessianException("hessian"));
|
||||
AppResponse mockRpcResult = new AppResponse();
|
||||
mockRpcResult.setException(new HessianException("hessian"));
|
||||
Result mockAsyncResult = AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation);
|
||||
|
||||
|
||||
Invoker<DemoService> invoker = mock(Invoker.class);
|
||||
when(invoker.invoke(invocation)).thenReturn(rpcResult);
|
||||
when(invoker.invoke(invocation)).thenReturn(mockAsyncResult);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result newResult = exceptionFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = exceptionFilter.invoke(invoker, invocation);
|
||||
|
||||
newResult = exceptionFilter.onResponse(newResult, invoker, invocation);
|
||||
AppResponse appResponse = (AppResponse) asyncResult.get();
|
||||
exceptionFilter.listener().onResponse(appResponse, invoker, invocation);
|
||||
|
||||
Assertions.assertFalse(newResult.getException() instanceof HessianException);
|
||||
|
||||
Assertions.assertEquals(newResult.getException().getClass(), RuntimeException.class);
|
||||
Assertions.assertEquals(newResult.getException().getMessage(), StringUtils.toString(rpcResult.getException()));
|
||||
Assertions.assertFalse(appResponse.getException() instanceof HessianException);
|
||||
|
||||
Assertions.assertEquals(appResponse.getException().getClass(), RuntimeException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,11 +17,11 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.RpcStatus;
|
||||
import org.apache.dubbo.rpc.support.BlockMyInvoker;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ public class ExecuteLimitFilterTest {
|
|||
@Test
|
||||
public void testNoExecuteLimitInvoke() throws Exception {
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
when(invoker.getUrl()).thenReturn(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1"));
|
||||
|
||||
Invocation invocation = Mockito.mock(Invocation.class);
|
||||
|
|
@ -56,7 +56,7 @@ public class ExecuteLimitFilterTest {
|
|||
@Test
|
||||
public void testExecuteLimitInvoke() throws Exception {
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
when(invoker.getUrl()).thenReturn(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&executes=10"));
|
||||
|
||||
Invocation invocation = Mockito.mock(Invocation.class);
|
||||
|
|
@ -82,6 +82,7 @@ public class ExecuteLimitFilterTest {
|
|||
executeLimitFilter.invoke(invoker, invocation);
|
||||
} catch (Exception e) {
|
||||
Assertions.assertTrue(e instanceof RpcException);
|
||||
executeLimitFilter.listener().onError(e, invoker, invocation);
|
||||
}
|
||||
Assertions.assertEquals(1, RpcStatus.getStatus(url, invocation.getMethodName()).getFailed());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,13 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.*;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
import org.apache.dubbo.rpc.support.Person;
|
||||
|
|
@ -54,14 +60,16 @@ public class GenericFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" +
|
||||
"accesslog=true&group=dubbo&version=1.1");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10)));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(AsyncRpcResult.newDefaultAsyncResult(new Person("person", 10), invocation));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result result = genericFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = genericFilter.invoke(invoker, invocation);
|
||||
|
||||
Assertions.assertEquals(HashMap.class, result.getValue().getClass());
|
||||
Assertions.assertEquals(10, ((HashMap) result.getValue()).get("age"));
|
||||
AppResponse appResponse = (AppResponse) asyncResult.get();
|
||||
genericFilter.listener().onResponse(appResponse, invoker, invocation);
|
||||
Assertions.assertEquals(HashMap.class, appResponse.getValue().getClass());
|
||||
Assertions.assertEquals(10, ((HashMap) appResponse.getValue()).get("age"));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +89,7 @@ public class GenericFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" +
|
||||
"accesslog=true&group=dubbo&version=1.1");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10)));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse(new Person("person", 10)));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
|
|
@ -104,7 +112,7 @@ public class GenericFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" +
|
||||
"accesslog=true&group=dubbo&version=1.1");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10)));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse(new Person("person", 10)));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
|
|
@ -128,7 +136,7 @@ public class GenericFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" +
|
||||
"accesslog=true&group=dubbo&version=1.1");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10)));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse(new Person("person", 10)));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.service.GenericException;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
import org.apache.dubbo.rpc.support.DemoService;
|
||||
|
|
@ -60,11 +61,14 @@ public class GenericImplFilterTest {
|
|||
person.put("name", "dubbo");
|
||||
person.put("age", 10);
|
||||
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(person));
|
||||
AppResponse mockRpcResult = new AppResponse(person);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result result = genericImplFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = genericImplFilter.invoke(invoker, invocation);
|
||||
Result result = asyncResult.get();
|
||||
genericImplFilter.listener().onResponse(result, invoker, invocation);
|
||||
|
||||
Assertions.assertEquals(Person.class, result.getValue().getClass());
|
||||
Assertions.assertEquals(10, ((Person) result.getValue()).getAge());
|
||||
|
|
@ -80,12 +84,14 @@ public class GenericImplFilterTest {
|
|||
"accesslog=true&group=dubbo&version=1.1&generic=true");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(
|
||||
new RpcResult(new GenericException(new RuntimeException("failed"))));
|
||||
AppResponse mockRpcResult = new AppResponse(new GenericException(new RuntimeException("failed")));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.getInterface()).thenReturn(DemoService.class);
|
||||
|
||||
Result result = genericImplFilter.invoke(invoker, invocation);
|
||||
Result asyncResult = genericImplFilter.invoke(invoker, invocation);
|
||||
Result result = asyncResult.get();
|
||||
genericImplFilter.listener().onResponse(result, invoker, invocation);
|
||||
Assertions.assertEquals(RuntimeException.class, result.getException().getClass());
|
||||
|
||||
}
|
||||
|
|
@ -105,7 +111,7 @@ public class GenericImplFilterTest {
|
|||
URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" +
|
||||
"accesslog=true&group=dubbo&version=1.1&generic=true");
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10)));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse(new Person("person", 10)));
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
|
||||
genericImplFilter.invoke(invoker, invocation);
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
import org.apache.dubbo.rpc.support.BlockMyInvoker;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -39,7 +39,7 @@ public class TimeoutFilterTest {
|
|||
int timeout = 3000;
|
||||
|
||||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
when(invoker.getUrl()).thenReturn(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&timeout=" + timeout));
|
||||
|
||||
Invocation invocation = Mockito.mock(Invocation.class);
|
||||
|
|
@ -60,7 +60,7 @@ public class TimeoutFilterTest {
|
|||
when(invocation.getMethodName()).thenReturn("testInvokeWithTimeout");
|
||||
|
||||
Result result = timeoutFilter.invoke(invoker, invocation);
|
||||
Assertions.assertEquals("alibaba", result.getValue());
|
||||
Assertions.assertEquals("Dubbo", result.getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package org.apache.dubbo.rpc.filter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -46,7 +46,7 @@ public class TokenFilterTest {
|
|||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&token=" + token);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
attachments.put(TOKEN_KEY, token);
|
||||
|
|
@ -65,7 +65,7 @@ public class TokenFilterTest {
|
|||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&token=" + token);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
|
||||
Map<String, String> attachments = new HashMap<String, String>();
|
||||
attachments.put(TOKEN_KEY, "wrongToken");
|
||||
|
|
@ -84,7 +84,7 @@ public class TokenFilterTest {
|
|||
Invoker invoker = Mockito.mock(Invoker.class);
|
||||
URL url = URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&token=" + token);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult("result"));
|
||||
when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse("result"));
|
||||
|
||||
Invocation invocation = Mockito.mock(Invocation.class);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@
|
|||
package org.apache.dubbo.rpc.support;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcResult;
|
||||
|
||||
public class BlockMyInvoker<T> extends MyInvoker<T> {
|
||||
|
||||
|
|
@ -38,19 +39,18 @@ public class BlockMyInvoker<T> extends MyInvoker<T> {
|
|||
|
||||
@Override
|
||||
public Result invoke(Invocation invocation) throws RpcException {
|
||||
RpcResult result = new RpcResult();
|
||||
AppResponse result = new AppResponse();
|
||||
if (hasException == false) {
|
||||
try {
|
||||
Thread.sleep(blockTime);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
result.setValue("alibaba");
|
||||
return result;
|
||||
result.setValue("Dubbo");
|
||||
} else {
|
||||
result.setException(new RuntimeException("mocked exception"));
|
||||
return result;
|
||||
}
|
||||
|
||||
return AsyncRpcResult.newDefaultAsyncResult(result, invocation);
|
||||
}
|
||||
|
||||
public long getBlockTime() {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue