From 55d77b764266c95d83b0bbe6ba8dbd998811ed81 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 25 May 2018 17:10:15 +0800 Subject: [PATCH 01/39] Async support start --- .../alibaba/dubbo/demo/consumer/Consumer.java | 1 + .../exchange/support/DefaultFuture.java | 2 ++ .../com/alibaba/dubbo/rpc/AsyncContext.java | 20 ++++++++++++++++ .../alibaba/dubbo/rpc/AsyncContextImpl.java | 20 ++++++++++++++++ .../alibaba/dubbo/rpc/PostProcessFilter.java | 23 ++++++++++++++++++ .../com/alibaba/dubbo/rpc/RpcContext.java | 13 ++++++++++ .../alibaba/dubbo/rpc/filter/EchoFilter.java | 10 ++++++-- .../rpc/protocol/dubbo/FutureAdapter.java | 24 +++++++++++++++++-- pom.xml | 4 ++-- 9 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index 9caacbc7ad7..d6a83357101 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -17,6 +17,7 @@ package com.alibaba.dubbo.demo.consumer; import com.alibaba.dubbo.demo.DemoService; + import org.springframework.context.support.ClassPathXmlApplicationContext; public class Consumer { diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java index eccc86d4815..25326104714 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java @@ -47,6 +47,8 @@ public class DefaultFuture implements ResponseFuture { private static final Map FUTURES = new ConcurrentHashMap(); + private static final Map> + static { Thread th = new Thread(new RemotingInvocationTimeoutScan(), "DubboResponseTimeoutScanTimer"); th.setDaemon(true); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java new file mode 100644 index 00000000000..4c3848e96e2 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +public interface AsyncContext { +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java new file mode 100644 index 00000000000..d2121b71a1e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +public class AsyncContextImpl implements AsyncContext { +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java new file mode 100644 index 00000000000..f23caf0ca11 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +public interface PostProcessFilter extends Filter { + + void postProcess(Invoker invoker, Invocation invocation, Result result); + +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java index bf56e2d12d4..0cc6764701a 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; @@ -171,6 +172,18 @@ public boolean isConsumerSide() { return getUrl().getParameter(Constants.SIDE_KEY, Constants.PROVIDER_SIDE).equals(Constants.CONSUMER_SIDE); } + /** + * get CompletableFuture. + * + * @param + * @return future + */ + @SuppressWarnings("unchecked") + public CompletableFuture getCompletableFuture() { + return (CompletableFuture) future; + } + + /** * get future. * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java index 134c496c848..d07ae1ce22f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java @@ -18,9 +18,9 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.rpc.Filter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.PostProcessFilter; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcResult; @@ -29,7 +29,7 @@ * EchoInvokerFilter */ @Activate(group = Constants.PROVIDER, order = -110000) -public class EchoFilter implements Filter { +public class EchoFilter implements PostProcessFilter { @Override public Result invoke(Invoker invoker, Invocation inv) throws RpcException { @@ -38,4 +38,10 @@ public Result invoke(Invoker invoker, Invocation inv) throws RpcException { return invoker.invoke(inv); } + @Override + public void postProcess(Invoker invoker, Invocation invocation, Result result) { + System.out.println("Post process for result: " + result.getValue()); + System.out.println("The next invoker in chain is: " + invoker); + + } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java index 4a534f0957e..9fc478e9d1c 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java @@ -18,24 +18,43 @@ import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.remoting.RemotingException; +import com.alibaba.dubbo.remoting.exchange.ResponseCallback; import com.alibaba.dubbo.remoting.exchange.ResponseFuture; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcException; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * FutureAdapter */ -public class FutureAdapter implements Future { +public class FutureAdapter extends CompletableFuture { private final ResponseFuture future; public FutureAdapter(ResponseFuture future) { this.future = future; + future.setCallback(new ResponseCallback() { + @Override + public void done(Object response) { + Result result = (Result) response; + V value = null; + try { + value = (V) result.recreate(); + } catch (Throwable t) { + FutureAdapter.this.completeExceptionally(t); + } + FutureAdapter.this.complete(value); + } + + @Override + public void caught(Throwable exception) { + FutureAdapter.this.completeExceptionally(exception); + } + }); } public ResponseFuture getFuture() { @@ -84,4 +103,5 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution } } + } diff --git a/pom.xml b/pom.xml index c8536aef145..68e0cef7858 100644 --- a/pom.xml +++ b/pom.xml @@ -106,8 +106,8 @@ oss - 1.6 - 1.6 + 1.8 + 1.8 UTF-8 3.0.2 From 6aec4d25aaba2d72e9f64dc54edbd4d487f471a8 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 28 May 2018 20:25:09 +0800 Subject: [PATCH 02/39] A basically worked version for provider async --- .../rpc/cluster/support/ClusterUtils.java | 3 + .../remoting/exchange/ExchangeHandler.java | 4 +- .../exchange/support/DefaultFuture.java | 2 - .../support/ExchangeHandlerAdapter.java | 4 +- .../support/ExchangeHandlerDispatcher.java | 6 +- .../support/header/HeaderExchangeHandler.java | 10 ++- .../dubbo/remoting/PerformanceServerTest.java | 9 +-- .../handler/HeaderExchangeHandlerTest.java | 11 ++-- .../support/header/HeartbeatHandlerTest.java | 6 +- dubbo-rpc/dubbo-rpc-api/pom.xml | 5 ++ .../com/alibaba/dubbo/rpc/AsyncContext.java | 10 +++ .../alibaba/dubbo/rpc/AsyncContextImpl.java | 65 +++++++++++++++++++ .../com/alibaba/dubbo/rpc/RpcContext.java | 53 ++++++++++++--- .../dubbo/rpc/filter/ContextFilter.java | 1 + .../rpc/protocol/dubbo/DubboProtocol.java | 25 +++++-- .../rpc/protocol/thrift/ThriftProtocol.java | 6 +- dubbo-test/dubbo-test-benchmark/pom.xml | 4 +- .../benchmark/AbstractBenchmarkServer.java | 5 +- 18 files changed, 189 insertions(+), 40 deletions(-) diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java index 7bc6f30f7f0..9739f553aeb 100644 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java +++ b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java @@ -60,6 +60,9 @@ public static URL mergeUrl(URL remoteUrl, Map localMap) { map.remove(Constants.TRANSPORTER_KEY); map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY); + + map.remove(Constants.ASYNC_KEY); + map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ASYNC_KEY); } if (localMap != null && localMap.size() > 0) { diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java index 76dcdc584bf..8d8f28445df 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java @@ -20,6 +20,8 @@ import com.alibaba.dubbo.remoting.RemotingException; import com.alibaba.dubbo.remoting.telnet.TelnetHandler; +import java.util.concurrent.CompletableFuture; + /** * ExchangeHandler. (API, Prototype, ThreadSafe) */ @@ -33,6 +35,6 @@ public interface ExchangeHandler extends ChannelHandler, TelnetHandler { * @return response * @throws RemotingException */ - Object reply(ExchangeChannel channel, Object request) throws RemotingException; + CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException; } \ No newline at end of file diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java index 25326104714..eccc86d4815 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/DefaultFuture.java @@ -47,8 +47,6 @@ public class DefaultFuture implements ResponseFuture { private static final Map FUTURES = new ConcurrentHashMap(); - private static final Map> - static { Thread th = new Thread(new RemotingInvocationTimeoutScan(), "DubboResponseTimeoutScanTimer"); th.setDaemon(true); diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java index 9deb434c9a0..8dd1d7a3a94 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java @@ -21,13 +21,15 @@ import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; +import java.util.concurrent.CompletableFuture; + /** * ExchangeHandlerAdapter */ public abstract class ExchangeHandlerAdapter extends TelnetHandlerAdapter implements ExchangeHandler { @Override - public Object reply(ExchangeChannel channel, Object msg) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object msg) throws RemotingException { return null; } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java index 179ba92e243..1e455884dfc 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java @@ -25,6 +25,8 @@ import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; import com.alibaba.dubbo.remoting.transport.ChannelHandlerDispatcher; +import java.util.concurrent.CompletableFuture; + /** * ExchangeHandlerDispatcher */ @@ -82,8 +84,8 @@ public ExchangeHandlerDispatcher removeReplier(Class type) { @Override @SuppressWarnings({"unchecked", "rawtypes"}) - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { - return ((Replier) replierDispatcher).reply(channel, request); + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { + return CompletableFuture.completedFuture(((Replier) replierDispatcher).reply(channel, request)); } @Override diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java index 3c378178e1b..db5fd0277f3 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -34,6 +34,7 @@ import com.alibaba.dubbo.remoting.transport.ChannelHandlerDelegate; import java.net.InetSocketAddress; +import java.util.concurrent.CompletableFuture; /** * ExchangeReceiver @@ -93,9 +94,9 @@ Response handleRequest(ExchangeChannel channel, Request req) throws RemotingExce Object msg = req.getData(); try { // handle data. - Object result = handler.reply(channel, msg); + CompletableFuture future = handler.reply(channel, msg); res.setStatus(Response.OK); - res.setResult(result); + res.setResult(future.get()); } catch (Throwable e) { res.setStatus(Response.SERVICE_ERROR); res.setErrorMessage(StringUtils.toString(e)); @@ -170,7 +171,10 @@ public void received(Channel channel, Object message) throws RemotingException { } else { if (request.isTwoWay()) { Response response = handleRequest(exchangeChannel, request); - channel.send(response); + // TODO Do we need to send back for Callback usage? + if (response.getStatus() != Response.OK || response.getResult() != null) { + channel.send(response); + } } else { handler.received(exchangeChannel, request.getData()); } diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java index fcababd5445..e021df0c4e9 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java +++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; /** * PerformanceServer @@ -78,17 +79,17 @@ public String telnet(Channel channel, String message) throws RemotingException { return "echo: " + message + "\r\ntelnet> "; } - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { if ("environment".equals(request)) { - return PerformanceUtils.getEnvironment(); + return CompletableFuture.completedFuture(PerformanceUtils.getEnvironment()); } if ("scene".equals(request)) { List scene = new ArrayList(); scene.add("Transporter: " + transporter); scene.add("Service Threads: " + threads); - return scene; + return CompletableFuture.completedFuture(scene); } - return request; + return CompletableFuture.completedFuture(request); } }); diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java index c3da46659ba..ff533098ada 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java +++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java @@ -29,6 +29,7 @@ import org.junit.Assert; import org.junit.Test; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; //TODO response test @@ -75,8 +76,8 @@ public void send(Object message) throws RemotingException { }; ExchangeHandler exhandler = new MockedExchangeHandler() { @Override - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { - return request; + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { + return CompletableFuture.completedFuture(request); } @Override @@ -116,7 +117,7 @@ public void send(Object message) throws RemotingException { }; ExchangeHandler exhandler = new MockedExchangeHandler() { @Override - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { throw new BizException(); } }; @@ -177,7 +178,7 @@ public void send(Object message) throws RemotingException { HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(new MockedExchangeHandler() { @Override - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { Assert.fail(); throw new RemotingException(channel, ""); } @@ -201,7 +202,7 @@ public String telnet(Channel channel, String message) throws RemotingException { throw new UnsupportedOperationException(); } - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { throw new UnsupportedOperationException(); } } diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java index 89fc6f44b56..58450394705 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java @@ -34,6 +34,8 @@ import org.junit.After; import org.junit.Test; +import java.util.concurrent.CompletableFuture; + public class HeartbeatHandlerTest { private static final Logger logger = LoggerFactory.getLogger(HeartbeatHandlerTest.class); @@ -107,8 +109,8 @@ class TestHeartbeatHandler implements ExchangeHandler { public int disconnectCount = 0; public int connectCount = 0; - public Object reply(ExchangeChannel channel, Object request) throws RemotingException { - return request; + public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { + return CompletableFuture.completedFuture(request); } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index c04c63498f9..7f08886c147 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -40,5 +40,10 @@ dubbo-serialization-api ${project.parent.version} + + com.alibaba + dubbo-remoting-api + ${project.parent.version} + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java index 4c3848e96e2..92bd283d951 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java @@ -17,4 +17,14 @@ package com.alibaba.dubbo.rpc; public interface AsyncContext { + + void addListener(Runnable run); + + void write(Object value); + + boolean isAsyncStarted(); + + void stop(); + + void start(); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index d2121b71a1e..6ad3d898b0b 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -16,5 +16,70 @@ */ package com.alibaba.dubbo.rpc; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.remoting.Channel; + +import java.util.concurrent.CompletableFuture; + public class AsyncContextImpl implements AsyncContext { + private static final Logger logger = LoggerFactory.getLogger(AsyncContextImpl.class); + + private boolean started = false; + + private CompletableFuture future; + + public AsyncContextImpl() { + } + + public AsyncContextImpl(Channel channel, CompletableFuture future) { + this.future = future; + /*this.future.whenCompleteAsync((result, t) -> { + Response res = new Response(); + try { + if (t == null) { + res.setStatus(Response.OK); + res.setResult(result); + } else { + res.setStatus(Response.SERVICE_ERROR); + res.setErrorMessage(StringUtils.toString(t)); + } + channel.send(res); + } catch (RemotingException e) { + logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e); + } finally { + // HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + });*/ + } + + @Override + public void addListener(Runnable run) { + + } + + @Override + public void write(Object value) { + if (value instanceof Throwable) { + // TODO check exception type like ExceptionFilter do. + } + Result result = new RpcResult(value); + future.complete(result); + } + + @Override + public boolean isAsyncStarted() { + return started; + } + + @Override + public void stop() { + this.started = false; + future.cancel(true); + } + + @Override + public void start() { + this.started = true; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java index 0cc6764701a..75852e1a982 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -85,6 +85,7 @@ protected RpcContext initialValue() { // we want these objects to be as generic as possible private Object request; private Object response; + private AsyncContext asyncContext; protected RpcContext() { } @@ -107,6 +108,23 @@ public static void removeContext() { LOCAL.remove(); } + /** + * TODO call multiple times in different thread? + * + * @return + * @throws IllegalStateException + */ + @SuppressWarnings("unchecked") + public static AsyncContext startAsync() throws IllegalStateException { + RpcContext currentContext = getContext(); + if (currentContext.asyncContext != null) { + currentContext.asyncContext.start(); + return currentContext.asyncContext; + } else { + throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); + } + } + /** * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest * @@ -116,6 +134,10 @@ public Object getRequest() { return request; } + public void setRequest(Object request) { + this.request = request; + } + /** * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest * @@ -126,11 +148,6 @@ public T getRequest(Class clazz) { return (request != null && clazz.isAssignableFrom(request.getClass())) ? (T) request : null; } - - public void setRequest(Object request) { - this.request = request; - } - /** * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse * @@ -140,6 +157,10 @@ public Object getResponse() { return response; } + public void setResponse(Object response) { + this.response = response; + } + /** * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse * @@ -150,10 +171,6 @@ public T getResponse(Class clazz) { return (response != null && clazz.isAssignableFrom(response.getClass())) ? (T) response : null; } - public void setResponse(Object response) { - this.response = response; - } - /** * is provider side. * @@ -183,7 +200,6 @@ public CompletableFuture getCompletableFuture() { return (CompletableFuture) future; } - /** * get future. * @@ -668,4 +684,21 @@ public void asyncCall(Runnable runnable) { removeAttachment(Constants.RETURN_KEY); } } + + public boolean isAsyncStarted() { + if (this.asyncContext == null) { + return false; + } + return asyncContext.isAsyncStarted(); + } + + public void stopAsync() { + // TODO mark somewhere + asyncContext.stop(); + asyncContext = null; + } + + public void setAsyncContext(AsyncContext asyncContext) { + this.asyncContext = asyncContext; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java index d0b7da145e5..8012fe20591 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java @@ -71,6 +71,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept try { return invoker.invoke(invocation); } finally { + // TODO must we remove the whole context completely? RpcContext.removeContext(); } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 4e8b971328d..81ebd2299ab 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -34,10 +34,12 @@ import com.alibaba.dubbo.remoting.exchange.ExchangeServer; import com.alibaba.dubbo.remoting.exchange.Exchangers; import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; +import com.alibaba.dubbo.rpc.AsyncContextImpl; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcInvocation; @@ -49,6 +51,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -72,7 +75,7 @@ public class DubboProtocol extends AbstractProtocol { private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { @Override - public Object reply(ExchangeChannel channel, Object message) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object message) throws RemotingException { if (message instanceof Invocation) { Invocation inv = (Invocation) message; Invoker invoker = getInvoker(channel, inv); @@ -80,7 +83,7 @@ public Object reply(ExchangeChannel channel, Object message) throws RemotingExce if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) { String methodsStr = invoker.getUrl().getParameters().get("methods"); boolean hasMethod = false; - if (methodsStr == null || methodsStr.indexOf(",") == -1) { + if (methodsStr == null || !methodsStr.contains(",")) { hasMethod = inv.getMethodName().equals(methodsStr); } else { String[] methods = methodsStr.split(","); @@ -99,8 +102,22 @@ public Object reply(ExchangeChannel channel, Object message) throws RemotingExce return null; } } - RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress()); - return invoker.invoke(inv); + boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); + CompletableFuture resultFuture = new CompletableFuture<>(); + RpcContext rpcContext = RpcContext.getContext(); + if (supportServerAsync) { + rpcContext.setAsyncContext(new AsyncContextImpl(channel, resultFuture)); + } + rpcContext.setRemoteAddress(channel.getRemoteAddress()); + Result result = invoker.invoke(inv); + if (!rpcContext.isAsyncStarted()) { + resultFuture.complete(result); + } else if (rpcContext.isAsyncStarted() && result.hasException()) { + rpcContext.stopAsync(); + resultFuture.complete(result); + } + + return resultFuture; } throw new RemotingException(channel, "Unsupported request: " + (message == null ? null : (message.getClass().getName() + ": " + message)) diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java index c1fdcf19dc4..29254db3b57 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -55,7 +56,7 @@ public class ThriftProtocol extends AbstractProtocol { private ExchangeHandler handler = new ExchangeHandlerAdapter() { @Override - public Object reply(ExchangeChannel channel, Object msg) throws RemotingException { + public CompletableFuture reply(ExchangeChannel channel, Object msg) throws RemotingException { if (msg instanceof Invocation) { Invocation inv = (Invocation) msg; @@ -78,7 +79,8 @@ public Object reply(ExchangeChannel channel, Object msg) throws RemotingExceptio } RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress()); - return exporter.getInvoker().invoke(inv); + + return CompletableFuture.completedFuture(exporter.getInvoker().invoke(inv)); } diff --git a/dubbo-test/dubbo-test-benchmark/pom.xml b/dubbo-test/dubbo-test-benchmark/pom.xml index 1721940c344..fc620781914 100644 --- a/dubbo-test/dubbo-test-benchmark/pom.xml +++ b/dubbo-test/dubbo-test-benchmark/pom.xml @@ -56,8 +56,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.6 - 1.6 + 1.8 + 1.8 UTF-8 diff --git a/dubbo-test/dubbo-test-benchmark/src/main/java/com/alibaba/dubbo/rpc/benchmark/AbstractBenchmarkServer.java b/dubbo-test/dubbo-test-benchmark/src/main/java/com/alibaba/dubbo/rpc/benchmark/AbstractBenchmarkServer.java index 4baa986ff18..0e1f2292b92 100644 --- a/dubbo-test/dubbo-test-benchmark/src/main/java/com/alibaba/dubbo/rpc/benchmark/AbstractBenchmarkServer.java +++ b/dubbo-test/dubbo-test-benchmark/src/main/java/com/alibaba/dubbo/rpc/benchmark/AbstractBenchmarkServer.java @@ -23,6 +23,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.CompletableFuture; /** * Abstract benchmark server Usage: BenchmarkServer listenPort maxThreads responseSize @@ -56,8 +57,8 @@ public void run(String[] args) throws Exception { Exchangers.bind(url.toString(), new ExchangeHandlerAdapter() { @Override - public Object reply(ExchangeChannel channel, Object message) throws RemotingException { - return new ResponseObject(responseSize); // send response + public CompletableFuture reply(ExchangeChannel channel, Object message) throws RemotingException { + return CompletableFuture.completedFuture(new ResponseObject(responseSize)); // send response } }); } From 7b8e8e93d4a0642dd1d4c34e70ffd7aac9c7c1bf Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 28 May 2018 21:05:16 +0800 Subject: [PATCH 03/39] asynchronously send response --- .../support/header/HeaderExchangeHandler.java | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java index db5fd0277f3..cbbb0adb469 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -76,7 +76,7 @@ void handlerEvent(Channel channel, Request req) throws RemotingException { } } - Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException { + void handleRequest(ExchangeChannel channel, Request req) throws RemotingException { Response res = new Response(req.getId(), req.getVersion()); if (req.isBroken()) { Object data = req.getData(); @@ -88,20 +88,39 @@ Response handleRequest(ExchangeChannel channel, Request req) throws RemotingExce res.setErrorMessage("Fail to decode request due to: " + msg); res.setStatus(Response.BAD_REQUEST); - return res; + channel.send(res); + return; } // find handler by message class. Object msg = req.getData(); try { // handle data. CompletableFuture future = handler.reply(channel, msg); - res.setStatus(Response.OK); - res.setResult(future.get()); + if (future.isDone()) { + channel.send(future.get()); + return; + } + future.whenCompleteAsync((result, t) -> { + try { + if (t == null) { + res.setStatus(Response.OK); + res.setResult(result); + } else { + res.setStatus(Response.SERVICE_ERROR); + res.setErrorMessage(StringUtils.toString(t)); + } + channel.send(res); + } catch (RemotingException e) { + logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e); + } finally { + // HeaderExchangeChannel.removeChannelIfDisconnected(channel); + } + }); } catch (Throwable e) { res.setStatus(Response.SERVICE_ERROR); res.setErrorMessage(StringUtils.toString(e)); + channel.send(res); } - return res; } @Override @@ -170,11 +189,7 @@ public void received(Channel channel, Object message) throws RemotingException { handlerEvent(channel, request); } else { if (request.isTwoWay()) { - Response response = handleRequest(exchangeChannel, request); - // TODO Do we need to send back for Callback usage? - if (response.getStatus() != Response.OK || response.getResult() != null) { - channel.send(response); - } + handleRequest(exchangeChannel, request); } else { handler.received(exchangeChannel, request.getData()); } From 94c21b56dcb6e081ba734dcb6a4c7bdbe857013f Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 29 May 2018 10:31:28 +0800 Subject: [PATCH 04/39] should send Response for sync invoke --- .../exchange/support/header/HeaderExchangeHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java index cbbb0adb469..a025ccd61fe 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -97,7 +97,9 @@ void handleRequest(ExchangeChannel channel, Request req) throws RemotingExceptio // handle data. CompletableFuture future = handler.reply(channel, msg); if (future.isDone()) { - channel.send(future.get()); + res.setStatus(Response.OK); + res.setResult(future.get()); + channel.send(res); return; } future.whenCompleteAsync((result, t) -> { From 7d46be78a3262153a0818817765cb3eb300eb6ac Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 29 May 2018 10:57:51 +0800 Subject: [PATCH 05/39] demo --- .../META-INF/spring/dubbo-demo-consumer.xml | 2 +- .../dubbo/demo/provider/DemoServiceImpl.java | 34 +++++++++++++++---- .../META-INF/spring/dubbo-demo-provider.xml | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index a3ddebcc2ed..2474d4c92e1 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -26,7 +26,7 @@ - + diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index c5011963977..f35ed742a4b 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -17,17 +17,39 @@ package com.alibaba.dubbo.demo.provider; import com.alibaba.dubbo.demo.DemoService; -import com.alibaba.dubbo.rpc.RpcContext; - -import java.text.SimpleDateFormat; -import java.util.Date; public class DemoServiceImpl implements DemoService { - @Override + /*@Override public String sayHello(String name) { + final AsyncContext asyncContext = RpcContext.startAsync(); System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); + new Thread(() -> { + asyncContext.write("Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress()); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + return null; + }*/ + + @Override + public String sayHello(String name) { +// final AsyncContext asyncContext = RpcContext.startAsync(); +// System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); +// new Thread(() -> { +// asyncContext.write("Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress()); +// try { +// Thread.sleep(500); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// }).start(); +// return null; + + return "name"; } } diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index 727954bce02..d901976d9fb 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -25,7 +25,7 @@ - + From 6ee2b60fd6b0798c64f5bc2bb15e790c0dace27d Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 29 May 2018 19:18:03 +0800 Subject: [PATCH 06/39] Support method with Future return type. --- .../com/alibaba/dubbo/common/Constants.java | 2 + .../com/alibaba/dubbo/rpc/AsyncResult.java | 60 +++++++++++++++++++ .../rpc/proxy/InvokerInvocationHandler.java | 16 ++++- .../rpc/protocol/dubbo/AsyncRpcResult.java | 38 ++++++++++++ .../rpc/protocol/dubbo/DubboInvoker.java | 5 +- 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java create mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java index 55e86d0382f..ac7e0e8b3bb 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -281,6 +281,8 @@ public class Constants { public static final String ASYNC_KEY = "async"; + public static final String ASYNC_SUFFIX = "Async"; + public static final String RETURN_KEY = "return"; public static final String TOKEN_KEY = "token"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java new file mode 100644 index 00000000000..015c52c2645 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +import java.util.Map; + +/** + * + */ +public abstract class AsyncResult implements Result { + + @Override + public Object getValue() { + return null; + } + + @Override + public Throwable getException() { + return null; + } + + @Override + public boolean hasException() { + return false; + } + + @Override + public Object getResult() { + return null; + } + + @Override + public Map getAttachments() { + return null; + } + + @Override + public String getAttachment(String key) { + return null; + } + + @Override + public String getAttachment(String key, String defaultValue) { + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java index d9d18cf8009..912373c8f00 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java @@ -16,11 +16,13 @@ */ package com.alibaba.dubbo.rpc.proxy; +import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.RpcInvocation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; /** * InvokerHandler @@ -49,7 +51,19 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl if ("equals".equals(methodName) && parameterTypes.length == 1) { return invoker.equals(args[0]); } - return invoker.invoke(new RpcInvocation(method, args)).recreate(); + + RpcInvocation invocation; + if (methodName.endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class)) { + Class clazz = method.getDeclaringClass(); + String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); + Method syncMethod = clazz.getSuperclass().getMethod(syncMethodName, method.getParameterTypes()); + invocation = new RpcInvocation(syncMethod, args); + invocation.setAttachment(Constants.ASYNC_KEY, "true"); + } else { + invocation = new RpcInvocation(method, args); + } + return invoker.invoke(invocation).recreate(); } + } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java new file mode 100644 index 00000000000..01d3895fc5b --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc.protocol.dubbo; + +import com.alibaba.dubbo.rpc.AsyncResult; + +import java.util.concurrent.CompletableFuture; + +/** + * + */ +public class AsyncRpcResult extends AsyncResult { + + private CompletableFuture future; + + public AsyncRpcResult(CompletableFuture future) { + this.future = future; + } + + @Override + public Object recreate() throws Throwable { + return future; + } +} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 0c6ea37c00d..6f1c26426a9 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -88,8 +88,9 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { return new RpcResult(); } else if (isAsync) { ResponseFuture future = currentClient.request(inv, timeout); - RpcContext.getContext().setFuture(new FutureAdapter(future)); - return new RpcResult(); + FutureAdapter futureAdapter = new FutureAdapter<>(future); + RpcContext.getContext().setFuture(futureAdapter); + return new AsyncRpcResult<>(futureAdapter); } else { RpcContext.getContext().setFuture(null); return (Result) currentClient.request(inv, timeout).get(); From a1305f617a759153e4e2bc5efa43cf8e6b5a980e Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 13:24:06 +0800 Subject: [PATCH 07/39] Add async interface annotation and processor --- .../com/alibaba/dubbo/common/Constants.java | 4 + .../alibaba/dubbo/config/ReferenceConfig.java | 15 + dubbo-demo/dubbo-demo-api/pom.xml | 8 + .../async/AsyncAnnotationProcessor.java | 331 ++++++++++++++++++ .../dubbo/config/async/DubboAsync.java | 24 ++ .../dubbo/config/annotation/AsyncFor.java | 41 +++ dubbo-plugin/pom.xml | 2 + .../integration/RegistryProtocol.java | 4 +- dubbo-rpc/dubbo-rpc-api/pom.xml | 5 + .../dubbo/rpc/proxy/AbstractProxyFactory.java | 5 +- .../rpc/proxy/InvokerInvocationHandler.java | 7 +- .../alibaba/dubbo/rpc/support/RpcUtils.java | 11 + .../rpc/protocol/dubbo/AsyncRpcResult.java | 4 + .../rpc/protocol/dubbo/DubboInvoker.java | 8 +- 14 files changed, 462 insertions(+), 7 deletions(-) create mode 100644 dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java create mode 100644 dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java create mode 100644 dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java index ac7e0e8b3bb..23856317c87 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -281,6 +281,8 @@ public class Constants { public static final String ASYNC_KEY = "async"; + public static final String FUTURE_KEY = "async_future"; + public static final String ASYNC_SUFFIX = "Async"; public static final String RETURN_KEY = "return"; @@ -325,6 +327,8 @@ public class Constants { public static final String INTERFACE_KEY = "interface"; + public static final String INTERFACES = "interfaces"; + public static final String GENERIC_KEY = "generic"; public static final String FILE_KEY = "file"; diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java index 7b5175243a1..9d5e9dc4e6b 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java @@ -25,6 +25,7 @@ import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.config.annotation.AsyncFor; import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.model.ApplicationModel; import com.alibaba.dubbo.config.model.ConsumerModel; @@ -73,6 +74,7 @@ public class ReferenceConfig extends AbstractReferenceConfig { // interface name private String interfaceName; private Class interfaceClass; + private Class asyncInterfaceClass; // client type private String client; // url for peer-to-peer invocation @@ -278,6 +280,7 @@ private void init() { checkApplication(); checkStubAndMock(interfaceClass); Map map = new HashMap(); + resolveAsyncInterface(interfaceClass, map); Map attributes = new HashMap(); map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE); map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); @@ -435,6 +438,18 @@ private void checkDefault() { appendProperties(consumer); } + private void resolveAsyncInterface(Class interfaceClass, Map map) { + AsyncFor annotation = interfaceClass.getAnnotation(AsyncFor.class); + if (annotation == null) return; + Class target = annotation.value(); + if (!target.isAssignableFrom(interfaceClass)) return; + this.asyncInterfaceClass = interfaceClass; + this.interfaceClass = target; + setInterface(this.interfaceClass.getName()); + map.put(Constants.INTERFACES, interfaceClass.getName()); + } + + public Class getInterfaceClass() { if (interfaceClass != null) { return interfaceClass; diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index 9316cbaec30..713a8a5bd96 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -29,4 +29,12 @@ true + + + + com.alibaba + dubbo-config-api + compile + + \ No newline at end of file diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java new file mode 100644 index 00000000000..4acf707f7ff --- /dev/null +++ b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java @@ -0,0 +1,331 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.async; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.WildcardType; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.io.Writer; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes("com.alibaba.dubbo.async.DubboAsync") +public class AsyncAnnotationProcessor extends AbstractProcessor { + + private static final String OBJECT_NAME = "java.lang.Object"; + + private static final String FUTURE_NAME = "ListenableFuture"; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) return false; + Set elements = roundEnv.getElementsAnnotatedWith(DubboAsync.class); + if (elements == null || elements.isEmpty()) return false; + + for (Element element : elements) { + if (element.getKind() == ElementKind.INTERFACE) { + generateAsyncInterface((TypeElement) element); + } + } + + return false; + } + + private void generateAsyncInterface(TypeElement element) { + Name qualified = element.getQualifiedName(); + if (qualified == null) return; + String qualifiedName = qualified.toString(); + if (qualifiedName.length() == 0) return; + + + String className = element.getSimpleName().toString(); + PackageElement packageElement = (PackageElement) element.getEnclosingElement(); + String packageName = packageElement.getQualifiedName().toString(); + + + StringBuilder result = new StringBuilder(); + startAsyncInterface(result, qualifiedName, className, packageName); + generateAsyncMethods(result, element); + endAsyncInterface(result); + + Writer writer = null; + try { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(qualifiedName + "Async"); + if (sourceFile.getLastModified() > 0) return; + + writer = sourceFile.openWriter(); + writer.write(result.toString()); + writer.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "生成async接口失败"); + } finally { + close(writer); + } + } + + private void generateAsyncMethods(StringBuilder result, TypeElement typeElement) { + List elements = typeElement.getEnclosedElements(); + Set existMethods = extractExistMethods(elements); + for (Element element : elements) { + if (element.getKind() != ElementKind.METHOD) continue; + generateAsyncMethod(result, (ExecutableElement) element, existMethods); + } + } + + private Set extractExistMethods(List elements) { + Set result = new HashSet(); + for (Element element : elements) { + result.add(element.getSimpleName().toString()); + } + return result; + } + + private void generateAsyncMethod(StringBuilder result, ExecutableElement element, Set existMethods) { + String asyncMethodName = element.getSimpleName().toString() + "Async"; + if (existMethods.contains(asyncMethodName)) return; + + appendTypeParameters(result, element); + appendReturnType(result, element); + result.append(asyncMethodName).append('('); + appendParameters(result, element); + result.append(");"); + } + + //泛型参数 + private void appendTypeParameters(StringBuilder result, ExecutableElement element) { + List typeParameters = element.getTypeParameters(); + if (typeParameters == null || typeParameters.size() == 0) return; + + result.append("<"); + int i = 1; + for (TypeParameterElement typeParameter : typeParameters) { + result.append(typeParameter.getSimpleName().toString()); + appendBounds(result, typeParameter); + if (i++ < typeParameters.size()) result.append(","); + } + result.append("> "); + } + + //返回值 + private void appendReturnType(StringBuilder result, ExecutableElement element) { + TypeMirror returnType = element.getReturnType(); + if (returnType.getKind() == TypeKind.VOID) { + result.append(FUTURE_NAME).append(" "); + } else { + result.append(FUTURE_NAME).append('<').append(type2ReturnName(returnType)).append("> "); + } + } + + //参数 + private void appendParameters(StringBuilder result, ExecutableElement method) { + List parameters = method.getParameters(); + int i = 1; + for (VariableElement element : parameters) { + result.append(type2ParameterName(element.asType())).append(" ").append(element.getSimpleName().toString()); + if (i++ < parameters.size()) { + result.append(","); + } + } + } + + private void appendBounds(StringBuilder result, TypeParameterElement typeParameter) { + List bounds = typeParameter.getBounds(); + if (bounds == null || bounds.size() == 0) return; + if (bounds.size() == 1) { + String boundName = type2ReturnName(bounds.get(0)); + if (OBJECT_NAME.equals(boundName)) return; + } + + result.append(" extends "); + int i = 1; + for (TypeMirror bound : bounds) { + String boundName = type2ReturnName(bound); + result.append(boundName); + if (i < bounds.size()) result.append(","); + } + } + + private String type2ReturnName(TypeMirror typeMirror) { + TypeKind kind = typeMirror.getKind(); + if (kind == TypeKind.VOID) return ""; + if (kind == TypeKind.ARRAY) { + ArrayType arrayType = (ArrayType) typeMirror; + TypeMirror componentType = arrayType.getComponentType(); + return type2ReturnName(componentType) + "[]"; + } + if (kind == TypeKind.BOOLEAN) { + return "Boolean"; + } + if (kind == TypeKind.BYTE) { + return "Byte"; + } + if (kind == TypeKind.CHAR) { + return "Char"; + } + if (kind == TypeKind.DOUBLE) { + return "Double"; + } + if (kind == TypeKind.FLOAT) { + return "Float"; + } + if (kind == TypeKind.INT) { + return "Integer"; + } + if (kind == TypeKind.LONG) { + return "Long"; + } + if (kind == TypeKind.SHORT) { + return "Short"; + } + if (kind == TypeKind.DECLARED) { + DeclaredType declaredType = (DeclaredType) typeMirror; + Element element = declaredType.asElement(); + List typeArguments = declaredType.getTypeArguments(); + if (typeArguments == null || typeArguments.size() == 0) { + return typeName(element); + } + + StringBuilder result = new StringBuilder(); + result.append(typeName(element)).append("<"); + int i = 1; + for (TypeMirror typeArgument : typeArguments) { + result.append(type2ReturnName(typeArgument)); + if (i++ < typeArguments.size()) result.append(","); + } + result.append(">"); + return result.toString(); + } + if (kind == TypeKind.TYPEVAR) { + TypeVariable typeVariable = (TypeVariable) typeMirror; + return typeVariable.asElement().getSimpleName().toString(); + } + if (kind == TypeKind.WILDCARD) { + WildcardType wildcardType = (WildcardType) typeMirror; + StringBuilder result = new StringBuilder(); + result.append("?"); + appendSuperBound(result, wildcardType.getSuperBound()); + appendExtendsBound(result, wildcardType.getExtendsBound()); + return result.toString(); + } + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, kind.toString()); + return ""; + } + + private void appendExtendsBound(StringBuilder resut, TypeMirror extendsBound) { + if (extendsBound == null) return; + String name = type2ReturnName(extendsBound); + if (name.equals(OBJECT_NAME)) return; + resut.append(" extends ").append(name); + } + + private void appendSuperBound(StringBuilder result, TypeMirror superBound) { + if (superBound == null) return; + String name = type2ReturnName(superBound); + if (name.equals(OBJECT_NAME)) return; + result.append(" super ").append(name); + } + + private String type2ParameterName(TypeMirror typeMirror) { + TypeKind kind = typeMirror.getKind(); + if (kind == TypeKind.BOOLEAN) { + return "boolean"; + } + if (kind == TypeKind.BYTE) { + return "byte"; + } + if (kind == TypeKind.CHAR) { + return "char"; + } + if (kind == TypeKind.DOUBLE) { + return "double"; + } + if (kind == TypeKind.FLOAT) { + return "float"; + } + if (kind == TypeKind.INT) { + return "int"; + } + if (kind == TypeKind.LONG) { + return "long"; + } + if (kind == TypeKind.SHORT) { + return "short"; + } + return type2ReturnName(typeMirror); + } + + private String typeName(Element element) { + if (element.getKind() == ElementKind.CLASS + || element.getKind() == ElementKind.INTERFACE + || element.getKind() == ElementKind.ENUM) { + return ((TypeElement) element).getQualifiedName().toString(); + } + return element.getSimpleName().toString(); + } + + private void endAsyncInterface(StringBuilder result) { + result.append("\n}"); + } + + private void startAsyncInterface(StringBuilder result, String qualifiedName, String className, String packageName) { + result.append("package ").append(packageName).append(";\n"); + result.append("import com.google.common.util.concurrent.ListenableFuture;\n"); + result.append("@javax.annotation.Generated(\"com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor\")\n"); + result.append("@com.alibaba.dubbo.config.annotation.AsyncFor(").append(qualifiedName).append(".class)\n"); + result.append("public interface ").append(className).append("Async extends ").append(className).append(" {\n"); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private void close(Writer writer) { + if (writer == null) return; + try { + writer.close(); + } catch (IOException e) { + + } + } +} + diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java new file mode 100644 index 00000000000..49d86885b79 --- /dev/null +++ b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.async; + +/** + * + */ + +public @interface DubboAsync { +} diff --git a/dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java b/dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java new file mode 100644 index 00000000000..58ca6770d1b --- /dev/null +++ b/dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * TODO This definition should placed in module 'dubbo-config-api', but only can be done when "rpc" dependencies are removed from "dubbo-config-api" + * If an interface is annotated with AsyncFor, it will be treated as an async counterpart for the sync one. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +public @interface AsyncFor { + + /** + * The original sync-style interface + * + * @return + */ + Class value(); + +} diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml index ca0e8d94a22..2d03d2c919c 100644 --- a/dubbo-plugin/pom.xml +++ b/dubbo-plugin/pom.xml @@ -30,6 +30,8 @@ The registry module of dubbo project dubbo-qos + dubbo-async + dubbo-async-processer false diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java index fd414edd135..e077eed20c4 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java @@ -48,6 +48,7 @@ import java.util.concurrent.Executors; import static com.alibaba.dubbo.common.Constants.ACCEPT_FOREIGN_IP; +import static com.alibaba.dubbo.common.Constants.INTERFACES; import static com.alibaba.dubbo.common.Constants.QOS_ENABLE; import static com.alibaba.dubbo.common.Constants.QOS_PORT; import static com.alibaba.dubbo.common.Constants.VALIDATION_KEY; @@ -229,7 +230,8 @@ private URL getRegistedProviderUrl(final Invoker originInvoker) { .removeParameter(QOS_ENABLE) .removeParameter(QOS_PORT) .removeParameter(ACCEPT_FOREIGN_IP) - .removeParameter(VALIDATION_KEY); + .removeParameter(VALIDATION_KEY) + .removeParameter(INTERFACES); return registedProviderUrl; } diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index 7f08886c147..8e64b02512a 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -45,5 +45,10 @@ dubbo-remoting-api ${project.parent.version} + + com.alibaba + dubbo-async + ${project.parent.version} + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java index 21c350da9c1..f10cb3d7fd0 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java @@ -31,7 +31,7 @@ public abstract class AbstractProxyFactory implements ProxyFactory { @Override public T getProxy(Invoker invoker) throws RpcException { Class[] interfaces = null; - String config = invoker.getUrl().getParameter("interfaces"); + String config = invoker.getUrl().getParameter(Constants.INTERFACES); if (config != null && config.length() > 0) { String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); if (types != null && types.length > 0) { @@ -39,7 +39,8 @@ public T getProxy(Invoker invoker) throws RpcException { interfaces[0] = invoker.getInterface(); interfaces[1] = EchoService.class; for (int i = 0; i < types.length; i++) { - interfaces[i + 1] = ReflectUtils.forName(types[i]); + // TODO can we load successfully for a different classloader?. + interfaces[i + 2] = ReflectUtils.forName(types[i]); } } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java index 912373c8f00..488f6ca2518 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java @@ -19,10 +19,10 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.RpcUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.util.concurrent.CompletableFuture; /** * InvokerHandler @@ -53,11 +53,12 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } RpcInvocation invocation; - if (methodName.endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class)) { + if (RpcUtils.isAsyncFuture(method)) { Class clazz = method.getDeclaringClass(); String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); - Method syncMethod = clazz.getSuperclass().getMethod(syncMethodName, method.getParameterTypes()); + Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes()); invocation = new RpcInvocation(syncMethod, args); + invocation.setAttachment(Constants.FUTURE_KEY, "true"); invocation.setAttachment(Constants.ASYNC_KEY, "true"); } else { invocation = new RpcInvocation(method, args); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java index 14568ead1ce..d23175acd12 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java @@ -21,11 +21,13 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; +import com.alibaba.dubbo.config.annotation.AsyncFor; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.RpcInvocation; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicLong; /** @@ -155,6 +157,15 @@ public static boolean isAsync(URL url, Invocation inv) { return isAsync; } + public static boolean isAsyncFuture(URL url, Invocation inv) { + return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_KEY)); + } + + public static boolean isAsyncFuture(Method method) { + Class clazz = method.getDeclaringClass(); + return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class); + } + public static boolean isOneway(URL url, Invocation inv) { boolean isOneway; if (Boolean.FALSE.toString().equals(inv.getAttachment(Constants.RETURN_KEY))) { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java index 01d3895fc5b..94815dbc595 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java @@ -31,6 +31,10 @@ public AsyncRpcResult(CompletableFuture future) { this.future = future; } + public CompletableFuture getFuture() { + return future; + } + @Override public Object recreate() throws Throwable { return future; diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 6f1c26426a9..a929463678d 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -90,7 +90,13 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { ResponseFuture future = currentClient.request(inv, timeout); FutureAdapter futureAdapter = new FutureAdapter<>(future); RpcContext.getContext().setFuture(futureAdapter); - return new AsyncRpcResult<>(futureAdapter); + Result result; + if (RpcUtils.isAsyncFuture(getUrl(), inv)) { + result = new AsyncRpcResult<>(futureAdapter); + } else { + result = new RpcResult(); + } + return result; } else { RpcContext.getContext().setFuture(null); return (Result) currentClient.request(inv, timeout).get(); From c06ff03c6bf2c5eb996a46f6129e95a3df5fb0c2 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 13:35:28 +0800 Subject: [PATCH 08/39] demo --- .../alibaba/dubbo/demo/consumer/Consumer.java | 34 +++++++++++++++---- .../META-INF/spring/dubbo-demo-consumer.xml | 4 ++- .../dubbo/demo/provider/DemoServiceImpl.java | 29 +++++++++------- .../META-INF/spring/dubbo-demo-provider.xml | 2 +- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index d6a83357101..aab9f4d7114 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -17,9 +17,13 @@ package com.alibaba.dubbo.demo.consumer; import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.demo.DemoServiceAsync; +import com.alibaba.dubbo.rpc.RpcContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import java.util.concurrent.CompletableFuture; + public class Consumer { public static void main(String[] args) { @@ -28,19 +32,37 @@ public static void main(String[] args) { System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); - DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy + DemoService demoService = (DemoService) context.getBean("demoService1"); // get remote service proxy + +// while (true) { +// try { +// Thread.sleep(1000); +// String hello = demoService.sayHello("world"); +// System.out.println(hello); // call remote method +// CompletableFuture future = RpcContext.getContext().getCompletableFuture(); +// if (future != null) { +// System.out.println("Result from future: " + future.get()); +// } +// } catch (Throwable throwable) { +// throwable.printStackTrace(); +// } +// } + DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoService"); // get remote service proxy while (true) { try { Thread.sleep(1000); - String hello = demoService.sayHello("world"); // call remote method - System.out.println(hello); // get result - + CompletableFuture future = demoServiceAsync.sayHelloAsync("world"); + CompletableFuture future1 = RpcContext.getContext().getCompletableFuture(); + System.out.println("Result from future: " + future.get()); + if (future1 != null) { + System.out.println("Result from rpccontext future: " + future1.get()); + } + System.out.println("Sync call from async: " + demoServiceAsync.sayHello("sync")); + System.out.println("Sync call: " + demoService.sayHello("sync")); } catch (Throwable throwable) { throwable.printStackTrace(); } - - } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index 2474d4c92e1..bf84188fa10 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -30,6 +30,8 @@ - + + + \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index f35ed742a4b..14caf0ff0ad 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -17,6 +17,11 @@ package com.alibaba.dubbo.demo.provider; import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.rpc.AsyncContext; +import com.alibaba.dubbo.rpc.RpcContext; + +import java.text.SimpleDateFormat; +import java.util.Date; public class DemoServiceImpl implements DemoService { @@ -37,19 +42,19 @@ public String sayHello(String name) { @Override public String sayHello(String name) { -// final AsyncContext asyncContext = RpcContext.startAsync(); -// System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); -// new Thread(() -> { -// asyncContext.write("Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress()); -// try { -// Thread.sleep(500); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// }).start(); -// return null; + final AsyncContext asyncContext = RpcContext.startAsync(); + System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + new Thread(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from provider."); + }).start(); - return "name"; + throw new RuntimeException("Test app exception."); + // return null; } } diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index d901976d9fb..d487091adfc 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -34,6 +34,6 @@ - + \ No newline at end of file From 4a891d81fc2aa2cc630f380cc8937aca5753b25d Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 15:23:40 +0800 Subject: [PATCH 09/39] polish async interface processor --- .../dubbo/config/async/AsyncAnnotationProcessor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java index 4acf707f7ff..abbf7e35155 100644 --- a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java +++ b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java @@ -48,7 +48,7 @@ public class AsyncAnnotationProcessor extends AbstractProcessor { private static final String OBJECT_NAME = "java.lang.Object"; - private static final String FUTURE_NAME = "ListenableFuture"; + private static final String FUTURE_NAME = "CompletableFuture"; @Override public synchronized void init(ProcessingEnvironment processingEnv) { @@ -96,7 +96,7 @@ private void generateAsyncInterface(TypeElement element) { writer.write(result.toString()); writer.close(); } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "生成async接口失败"); + processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Failed to generate async interface."); } finally { close(writer); } @@ -130,7 +130,7 @@ private void generateAsyncMethod(StringBuilder result, ExecutableElement element result.append(");"); } - //泛型参数 + // generic parameter type private void appendTypeParameters(StringBuilder result, ExecutableElement element) { List typeParameters = element.getTypeParameters(); if (typeParameters == null || typeParameters.size() == 0) return; @@ -145,7 +145,7 @@ private void appendTypeParameters(StringBuilder result, ExecutableElement elemen result.append("> "); } - //返回值 + // return type private void appendReturnType(StringBuilder result, ExecutableElement element) { TypeMirror returnType = element.getReturnType(); if (returnType.getKind() == TypeKind.VOID) { @@ -155,7 +155,7 @@ private void appendReturnType(StringBuilder result, ExecutableElement element) { } } - //参数 + // parameters private void appendParameters(StringBuilder result, ExecutableElement method) { List parameters = method.getParameters(); int i = 1; @@ -308,7 +308,7 @@ private void endAsyncInterface(StringBuilder result) { private void startAsyncInterface(StringBuilder result, String qualifiedName, String className, String packageName) { result.append("package ").append(packageName).append(";\n"); - result.append("import com.google.common.util.concurrent.ListenableFuture;\n"); + result.append("import import java.util.concurrent.CompletableFuture;\n"); result.append("@javax.annotation.Generated(\"com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor\")\n"); result.append("@com.alibaba.dubbo.config.annotation.AsyncFor(").append(qualifiedName).append(".class)\n"); result.append("public interface ").append(className).append("Async extends ").append(className).append(" {\n"); From fcd30ec272c4d039a8ae51189ee7436e038b79c4 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 15:26:39 +0800 Subject: [PATCH 10/39] fix concurrent write back problem when use provider async. --- .../com/alibaba/dubbo/rpc/AsyncContext.java | 2 +- .../alibaba/dubbo/rpc/AsyncContextImpl.java | 48 ++++++++----------- .../alibaba/dubbo/rpc}/AsyncRpcResult.java | 4 +- .../com/alibaba/dubbo/rpc/RpcContext.java | 6 +-- .../rpc/protocol/dubbo/DubboInvoker.java | 1 + .../rpc/protocol/dubbo/DubboProtocol.java | 7 +-- 6 files changed, 29 insertions(+), 39 deletions(-) rename dubbo-rpc/{dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo => dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc}/AsyncRpcResult.java (93%) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java index 92bd283d951..f5e4e5cb15c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java @@ -24,7 +24,7 @@ public interface AsyncContext { boolean isAsyncStarted(); - void stop(); + boolean stop(); void start(); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index 6ad3d898b0b..7836a82d32e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -18,39 +18,22 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.remoting.Channel; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; public class AsyncContextImpl implements AsyncContext { private static final Logger logger = LoggerFactory.getLogger(AsyncContextImpl.class); - private boolean started = false; + private final AtomicBoolean started = new AtomicBoolean(false); private CompletableFuture future; public AsyncContextImpl() { } - public AsyncContextImpl(Channel channel, CompletableFuture future) { + public AsyncContextImpl(CompletableFuture future) { this.future = future; - /*this.future.whenCompleteAsync((result, t) -> { - Response res = new Response(); - try { - if (t == null) { - res.setStatus(Response.OK); - res.setResult(result); - } else { - res.setStatus(Response.SERVICE_ERROR); - res.setErrorMessage(StringUtils.toString(t)); - } - channel.send(res); - } catch (RemotingException e) { - logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e); - } finally { - // HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - });*/ } @Override @@ -60,26 +43,33 @@ public void addListener(Runnable run) { @Override public void write(Object value) { - if (value instanceof Throwable) { - // TODO check exception type like ExceptionFilter do. + if (stop()) { + if (value instanceof Throwable) { + // TODO check exception type like ExceptionFilter do. + } + Result result = new RpcResult(value); + future.complete(result); + } else { + throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); } - Result result = new RpcResult(value); - future.complete(result); } @Override public boolean isAsyncStarted() { - return started; + return started.get(); } @Override - public void stop() { - this.started = false; - future.cancel(true); + public boolean stop() { + if (started.compareAndSet(true, false)) { +// future.cancel(true); + return true; + } + return false; } @Override public void start() { - this.started = true; + this.started.set(true); } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java similarity index 93% rename from dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java rename to dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java index 94815dbc595..47b4166cfff 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java @@ -14,9 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc.protocol.dubbo; - -import com.alibaba.dubbo.rpc.AsyncResult; +package com.alibaba.dubbo.rpc; import java.util.concurrent.CompletableFuture; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java index 75852e1a982..560bb695078 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -692,10 +692,10 @@ public boolean isAsyncStarted() { return asyncContext.isAsyncStarted(); } - public void stopAsync() { - // TODO mark somewhere - asyncContext.stop(); + public boolean stopAsync() { + boolean stoped = asyncContext.stop(); asyncContext = null; + return stoped; } public void setAsyncContext(AsyncContext asyncContext) { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index a929463678d..1aabb943cf0 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -24,6 +24,7 @@ import com.alibaba.dubbo.remoting.TimeoutException; import com.alibaba.dubbo.remoting.exchange.ExchangeClient; import com.alibaba.dubbo.remoting.exchange.ResponseFuture; +import com.alibaba.dubbo.rpc.AsyncRpcResult; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 81ebd2299ab..01411730d41 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -106,15 +106,16 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) CompletableFuture resultFuture = new CompletableFuture<>(); RpcContext rpcContext = RpcContext.getContext(); if (supportServerAsync) { - rpcContext.setAsyncContext(new AsyncContextImpl(channel, resultFuture)); + rpcContext.setAsyncContext(new AsyncContextImpl(resultFuture)); } rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); if (!rpcContext.isAsyncStarted()) { resultFuture.complete(result); } else if (rpcContext.isAsyncStarted() && result.hasException()) { - rpcContext.stopAsync(); - resultFuture.complete(result); + if (rpcContext.stopAsync()) { + resultFuture.complete(result); + } } return resultFuture; From fe0fe6b89cfeabdef2b2b7185df856db8aa1725e Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 15:28:27 +0800 Subject: [PATCH 11/39] revert demo changes --- dubbo-demo/dubbo-demo-api/pom.xml | 8 ----- .../alibaba/dubbo/demo/consumer/Consumer.java | 34 ++++--------------- .../META-INF/spring/dubbo-demo-consumer.xml | 6 ++-- .../dubbo/demo/provider/DemoServiceImpl.java | 29 +--------------- .../META-INF/spring/dubbo-demo-provider.xml | 4 +-- 5 files changed, 11 insertions(+), 70 deletions(-) diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index 713a8a5bd96..9316cbaec30 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -29,12 +29,4 @@ true - - - - com.alibaba - dubbo-config-api - compile - - \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index aab9f4d7114..d6a83357101 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -17,13 +17,9 @@ package com.alibaba.dubbo.demo.consumer; import com.alibaba.dubbo.demo.DemoService; -import com.alibaba.dubbo.demo.DemoServiceAsync; -import com.alibaba.dubbo.rpc.RpcContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import java.util.concurrent.CompletableFuture; - public class Consumer { public static void main(String[] args) { @@ -32,37 +28,19 @@ public static void main(String[] args) { System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); - DemoService demoService = (DemoService) context.getBean("demoService1"); // get remote service proxy - -// while (true) { -// try { -// Thread.sleep(1000); -// String hello = demoService.sayHello("world"); -// System.out.println(hello); // call remote method -// CompletableFuture future = RpcContext.getContext().getCompletableFuture(); -// if (future != null) { -// System.out.println("Result from future: " + future.get()); -// } -// } catch (Throwable throwable) { -// throwable.printStackTrace(); -// } -// } + DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy - DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoService"); // get remote service proxy while (true) { try { Thread.sleep(1000); - CompletableFuture future = demoServiceAsync.sayHelloAsync("world"); - CompletableFuture future1 = RpcContext.getContext().getCompletableFuture(); - System.out.println("Result from future: " + future.get()); - if (future1 != null) { - System.out.println("Result from rpccontext future: " + future1.get()); - } - System.out.println("Sync call from async: " + demoServiceAsync.sayHello("sync")); - System.out.println("Sync call: " + demoService.sayHello("sync")); + String hello = demoService.sayHello("world"); // call remote method + System.out.println(hello); // get result + } catch (Throwable throwable) { throwable.printStackTrace(); } + + } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index bf84188fa10..a3ddebcc2ed 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -26,12 +26,10 @@ - + - - - + \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index 14caf0ff0ad..c5011963977 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -17,7 +17,6 @@ package com.alibaba.dubbo.demo.provider; import com.alibaba.dubbo.demo.DemoService; -import com.alibaba.dubbo.rpc.AsyncContext; import com.alibaba.dubbo.rpc.RpcContext; import java.text.SimpleDateFormat; @@ -25,36 +24,10 @@ public class DemoServiceImpl implements DemoService { - /*@Override - public String sayHello(String name) { - final AsyncContext asyncContext = RpcContext.startAsync(); - System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - new Thread(() -> { - asyncContext.write("Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress()); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }).start(); - return null; - }*/ - @Override public String sayHello(String name) { - final AsyncContext asyncContext = RpcContext.startAsync(); System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - new Thread(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - asyncContext.write("Hello " + name + ", response from provider."); - }).start(); - - throw new RuntimeException("Test app exception."); - // return null; + return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } } diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index d487091adfc..727954bce02 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -25,7 +25,7 @@ - + @@ -34,6 +34,6 @@ - + \ No newline at end of file From 77c52c2878d6cb2d5cb87c4257863efc6af22260 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 15:35:43 +0800 Subject: [PATCH 12/39] config async processor as spi. --- .../META-INF/services/javax.annotation.processing.Processor | 1 + 1 file changed, 1 insertion(+) create mode 100644 dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000000..103cc2d4428 --- /dev/null +++ b/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +com.alibaba.dubbo.config.async.AsyncAnnotationProcessor \ No newline at end of file From f2d0476532a8b04cde34fa3385cbb34147aba838 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 15:37:59 +0800 Subject: [PATCH 13/39] add missed pom files --- dubbo-plugin/dubbo-async-processer/pom.xml | 58 ++++++++++++++++++++++ dubbo-plugin/dubbo-async/pom.xml | 35 +++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 dubbo-plugin/dubbo-async-processer/pom.xml create mode 100644 dubbo-plugin/dubbo-async/pom.xml diff --git a/dubbo-plugin/dubbo-async-processer/pom.xml b/dubbo-plugin/dubbo-async-processer/pom.xml new file mode 100644 index 00000000000..eb0e1413643 --- /dev/null +++ b/dubbo-plugin/dubbo-async-processer/pom.xml @@ -0,0 +1,58 @@ + + + + com.alibaba + dubbo-plugin + 2.6.2-SNAPSHOT + + 4.0.0 + + dubbo-async-processer + jar + + dubbo-async-processer + + + UTF-8 + false + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/annotations + + + + + + + + diff --git a/dubbo-plugin/dubbo-async/pom.xml b/dubbo-plugin/dubbo-async/pom.xml new file mode 100644 index 00000000000..bd6f899b7f8 --- /dev/null +++ b/dubbo-plugin/dubbo-async/pom.xml @@ -0,0 +1,35 @@ + + + + com.alibaba + dubbo-plugin + 2.6.2-SNAPSHOT + + 4.0.0 + + dubbo-async + jar + + dubbo-async + + + UTF-8 + false + + From f1f0cf07ffe2399fbe8fbab0f33dd278c2c59b36 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 18:27:50 +0800 Subject: [PATCH 14/39] make DubboAsync work at source compile phase. --- dubbo-plugin/dubbo-async-processer/pom.xml | 29 +++++-------------- .../dubbo/config/async/DubboAsync.java | 10 ++++++- pom.xml | 1 + 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/dubbo-plugin/dubbo-async-processer/pom.xml b/dubbo-plugin/dubbo-async-processer/pom.xml index eb0e1413643..66394b09c19 100644 --- a/dubbo-plugin/dubbo-async-processer/pom.xml +++ b/dubbo-plugin/dubbo-async-processer/pom.xml @@ -33,26 +33,11 @@ false - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.10 - - - generate-sources - - add-source - - - - ${project.build.directory}/generated-sources/annotations - - - - - - - + + + com.alibaba + dubbo-async + ${project.version} + + diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java index 49d86885b79..847f6a35c17 100644 --- a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java +++ b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java @@ -16,9 +16,17 @@ */ package com.alibaba.dubbo.config.async; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * */ - +@Documented +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) public @interface DubboAsync { } diff --git a/pom.xml b/pom.xml index 68e0cef7858..0f82b99d29b 100644 --- a/pom.xml +++ b/pom.xml @@ -420,6 +420,7 @@ maven-compiler-plugin ${maven_compiler_version} + -proc:none true ${java_source_version} ${java_target_version} From 3e9ffb4d4724629dc2b6e99bf779d044fe461de5 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 20:23:49 +0800 Subject: [PATCH 15/39] change annotation value to array --- .../dubbo/config/async/AsyncAnnotationProcessor.java | 6 +++--- dubbo-test/dubbo-test-benchmark/pom.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java index abbf7e35155..73bdbc9bce3 100644 --- a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java +++ b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java @@ -43,7 +43,7 @@ import java.util.List; import java.util.Set; -@SupportedAnnotationTypes("com.alibaba.dubbo.async.DubboAsync") +@SupportedAnnotationTypes({"com.alibaba.dubbo.config.async.DubboAsync"}) public class AsyncAnnotationProcessor extends AbstractProcessor { private static final String OBJECT_NAME = "java.lang.Object"; @@ -308,7 +308,7 @@ private void endAsyncInterface(StringBuilder result) { private void startAsyncInterface(StringBuilder result, String qualifiedName, String className, String packageName) { result.append("package ").append(packageName).append(";\n"); - result.append("import import java.util.concurrent.CompletableFuture;\n"); + result.append("import java.util.concurrent.CompletableFuture;\n"); result.append("@javax.annotation.Generated(\"com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor\")\n"); result.append("@com.alibaba.dubbo.config.annotation.AsyncFor(").append(qualifiedName).append(".class)\n"); result.append("public interface ").append(className).append("Async extends ").append(className).append(" {\n"); @@ -316,7 +316,7 @@ private void startAsyncInterface(StringBuilder result, String qualifiedName, Str @Override public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latest(); + return SourceVersion.latestSupported(); } private void close(Writer writer) { diff --git a/dubbo-test/dubbo-test-benchmark/pom.xml b/dubbo-test/dubbo-test-benchmark/pom.xml index fc620781914..049e98b58ca 100644 --- a/dubbo-test/dubbo-test-benchmark/pom.xml +++ b/dubbo-test/dubbo-test-benchmark/pom.xml @@ -56,6 +56,7 @@ org.apache.maven.plugins maven-compiler-plugin + -proc:none 1.8 1.8 UTF-8 From ff22444188c1b53491412485fb68d3286df7c341 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 30 May 2018 20:58:41 +0800 Subject: [PATCH 16/39] transfer async-processor module to eco-system --- dubbo-plugin/dubbo-async-processer/pom.xml | 43 --- .../async/AsyncAnnotationProcessor.java | 331 ------------------ .../dubbo/config/async/DubboAsync.java | 32 -- .../javax.annotation.processing.Processor | 1 - dubbo-plugin/pom.xml | 1 - 5 files changed, 408 deletions(-) delete mode 100644 dubbo-plugin/dubbo-async-processer/pom.xml delete mode 100644 dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java delete mode 100644 dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java delete mode 100644 dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/dubbo-plugin/dubbo-async-processer/pom.xml b/dubbo-plugin/dubbo-async-processer/pom.xml deleted file mode 100644 index 66394b09c19..00000000000 --- a/dubbo-plugin/dubbo-async-processer/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - com.alibaba - dubbo-plugin - 2.6.2-SNAPSHOT - - 4.0.0 - - dubbo-async-processer - jar - - dubbo-async-processer - - - UTF-8 - false - - - - - com.alibaba - dubbo-async - ${project.version} - - - diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java deleted file mode 100644 index 73bdbc9bce3..00000000000 --- a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/AsyncAnnotationProcessor.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.config.async; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.WildcardType; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import java.io.IOException; -import java.io.Writer; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -@SupportedAnnotationTypes({"com.alibaba.dubbo.config.async.DubboAsync"}) -public class AsyncAnnotationProcessor extends AbstractProcessor { - - private static final String OBJECT_NAME = "java.lang.Object"; - - private static final String FUTURE_NAME = "CompletableFuture"; - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (roundEnv.processingOver()) return false; - Set elements = roundEnv.getElementsAnnotatedWith(DubboAsync.class); - if (elements == null || elements.isEmpty()) return false; - - for (Element element : elements) { - if (element.getKind() == ElementKind.INTERFACE) { - generateAsyncInterface((TypeElement) element); - } - } - - return false; - } - - private void generateAsyncInterface(TypeElement element) { - Name qualified = element.getQualifiedName(); - if (qualified == null) return; - String qualifiedName = qualified.toString(); - if (qualifiedName.length() == 0) return; - - - String className = element.getSimpleName().toString(); - PackageElement packageElement = (PackageElement) element.getEnclosingElement(); - String packageName = packageElement.getQualifiedName().toString(); - - - StringBuilder result = new StringBuilder(); - startAsyncInterface(result, qualifiedName, className, packageName); - generateAsyncMethods(result, element); - endAsyncInterface(result); - - Writer writer = null; - try { - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(qualifiedName + "Async"); - if (sourceFile.getLastModified() > 0) return; - - writer = sourceFile.openWriter(); - writer.write(result.toString()); - writer.close(); - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Failed to generate async interface."); - } finally { - close(writer); - } - } - - private void generateAsyncMethods(StringBuilder result, TypeElement typeElement) { - List elements = typeElement.getEnclosedElements(); - Set existMethods = extractExistMethods(elements); - for (Element element : elements) { - if (element.getKind() != ElementKind.METHOD) continue; - generateAsyncMethod(result, (ExecutableElement) element, existMethods); - } - } - - private Set extractExistMethods(List elements) { - Set result = new HashSet(); - for (Element element : elements) { - result.add(element.getSimpleName().toString()); - } - return result; - } - - private void generateAsyncMethod(StringBuilder result, ExecutableElement element, Set existMethods) { - String asyncMethodName = element.getSimpleName().toString() + "Async"; - if (existMethods.contains(asyncMethodName)) return; - - appendTypeParameters(result, element); - appendReturnType(result, element); - result.append(asyncMethodName).append('('); - appendParameters(result, element); - result.append(");"); - } - - // generic parameter type - private void appendTypeParameters(StringBuilder result, ExecutableElement element) { - List typeParameters = element.getTypeParameters(); - if (typeParameters == null || typeParameters.size() == 0) return; - - result.append("<"); - int i = 1; - for (TypeParameterElement typeParameter : typeParameters) { - result.append(typeParameter.getSimpleName().toString()); - appendBounds(result, typeParameter); - if (i++ < typeParameters.size()) result.append(","); - } - result.append("> "); - } - - // return type - private void appendReturnType(StringBuilder result, ExecutableElement element) { - TypeMirror returnType = element.getReturnType(); - if (returnType.getKind() == TypeKind.VOID) { - result.append(FUTURE_NAME).append(" "); - } else { - result.append(FUTURE_NAME).append('<').append(type2ReturnName(returnType)).append("> "); - } - } - - // parameters - private void appendParameters(StringBuilder result, ExecutableElement method) { - List parameters = method.getParameters(); - int i = 1; - for (VariableElement element : parameters) { - result.append(type2ParameterName(element.asType())).append(" ").append(element.getSimpleName().toString()); - if (i++ < parameters.size()) { - result.append(","); - } - } - } - - private void appendBounds(StringBuilder result, TypeParameterElement typeParameter) { - List bounds = typeParameter.getBounds(); - if (bounds == null || bounds.size() == 0) return; - if (bounds.size() == 1) { - String boundName = type2ReturnName(bounds.get(0)); - if (OBJECT_NAME.equals(boundName)) return; - } - - result.append(" extends "); - int i = 1; - for (TypeMirror bound : bounds) { - String boundName = type2ReturnName(bound); - result.append(boundName); - if (i < bounds.size()) result.append(","); - } - } - - private String type2ReturnName(TypeMirror typeMirror) { - TypeKind kind = typeMirror.getKind(); - if (kind == TypeKind.VOID) return ""; - if (kind == TypeKind.ARRAY) { - ArrayType arrayType = (ArrayType) typeMirror; - TypeMirror componentType = arrayType.getComponentType(); - return type2ReturnName(componentType) + "[]"; - } - if (kind == TypeKind.BOOLEAN) { - return "Boolean"; - } - if (kind == TypeKind.BYTE) { - return "Byte"; - } - if (kind == TypeKind.CHAR) { - return "Char"; - } - if (kind == TypeKind.DOUBLE) { - return "Double"; - } - if (kind == TypeKind.FLOAT) { - return "Float"; - } - if (kind == TypeKind.INT) { - return "Integer"; - } - if (kind == TypeKind.LONG) { - return "Long"; - } - if (kind == TypeKind.SHORT) { - return "Short"; - } - if (kind == TypeKind.DECLARED) { - DeclaredType declaredType = (DeclaredType) typeMirror; - Element element = declaredType.asElement(); - List typeArguments = declaredType.getTypeArguments(); - if (typeArguments == null || typeArguments.size() == 0) { - return typeName(element); - } - - StringBuilder result = new StringBuilder(); - result.append(typeName(element)).append("<"); - int i = 1; - for (TypeMirror typeArgument : typeArguments) { - result.append(type2ReturnName(typeArgument)); - if (i++ < typeArguments.size()) result.append(","); - } - result.append(">"); - return result.toString(); - } - if (kind == TypeKind.TYPEVAR) { - TypeVariable typeVariable = (TypeVariable) typeMirror; - return typeVariable.asElement().getSimpleName().toString(); - } - if (kind == TypeKind.WILDCARD) { - WildcardType wildcardType = (WildcardType) typeMirror; - StringBuilder result = new StringBuilder(); - result.append("?"); - appendSuperBound(result, wildcardType.getSuperBound()); - appendExtendsBound(result, wildcardType.getExtendsBound()); - return result.toString(); - } - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, kind.toString()); - return ""; - } - - private void appendExtendsBound(StringBuilder resut, TypeMirror extendsBound) { - if (extendsBound == null) return; - String name = type2ReturnName(extendsBound); - if (name.equals(OBJECT_NAME)) return; - resut.append(" extends ").append(name); - } - - private void appendSuperBound(StringBuilder result, TypeMirror superBound) { - if (superBound == null) return; - String name = type2ReturnName(superBound); - if (name.equals(OBJECT_NAME)) return; - result.append(" super ").append(name); - } - - private String type2ParameterName(TypeMirror typeMirror) { - TypeKind kind = typeMirror.getKind(); - if (kind == TypeKind.BOOLEAN) { - return "boolean"; - } - if (kind == TypeKind.BYTE) { - return "byte"; - } - if (kind == TypeKind.CHAR) { - return "char"; - } - if (kind == TypeKind.DOUBLE) { - return "double"; - } - if (kind == TypeKind.FLOAT) { - return "float"; - } - if (kind == TypeKind.INT) { - return "int"; - } - if (kind == TypeKind.LONG) { - return "long"; - } - if (kind == TypeKind.SHORT) { - return "short"; - } - return type2ReturnName(typeMirror); - } - - private String typeName(Element element) { - if (element.getKind() == ElementKind.CLASS - || element.getKind() == ElementKind.INTERFACE - || element.getKind() == ElementKind.ENUM) { - return ((TypeElement) element).getQualifiedName().toString(); - } - return element.getSimpleName().toString(); - } - - private void endAsyncInterface(StringBuilder result) { - result.append("\n}"); - } - - private void startAsyncInterface(StringBuilder result, String qualifiedName, String className, String packageName) { - result.append("package ").append(packageName).append(";\n"); - result.append("import java.util.concurrent.CompletableFuture;\n"); - result.append("@javax.annotation.Generated(\"com.alibaba.dubbo.async.processor.AsyncAnnotationProcessor\")\n"); - result.append("@com.alibaba.dubbo.config.annotation.AsyncFor(").append(qualifiedName).append(".class)\n"); - result.append("public interface ").append(className).append("Async extends ").append(className).append(" {\n"); - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - private void close(Writer writer) { - if (writer == null) return; - try { - writer.close(); - } catch (IOException e) { - - } - } -} - diff --git a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java b/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java deleted file mode 100644 index 847f6a35c17..00000000000 --- a/dubbo-plugin/dubbo-async-processer/src/main/java/com/alibaba/dubbo/config/async/DubboAsync.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.config.async; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * - */ -@Documented -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.SOURCE) -public @interface DubboAsync { -} diff --git a/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index 103cc2d4428..00000000000 --- a/dubbo-plugin/dubbo-async-processer/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1 +0,0 @@ -com.alibaba.dubbo.config.async.AsyncAnnotationProcessor \ No newline at end of file diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml index 2d03d2c919c..36f3229a7d1 100644 --- a/dubbo-plugin/pom.xml +++ b/dubbo-plugin/pom.xml @@ -31,7 +31,6 @@ dubbo-qos dubbo-async - dubbo-async-processer false From 0380d1b57fc9f73de2f0ef5e8bfd3124b2bc101b Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Thu, 31 May 2018 09:32:05 +0800 Subject: [PATCH 17/39] Fix NPE in UT --- .../remoting/exchange/support/header/HeaderExchangeChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java index 7b6bd8c43c7..db3f84fcfe9 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java @@ -74,7 +74,7 @@ static void removeChannelIfDisconnected(Channel ch) { @Override public void send(Object message) throws RemotingException { - send(message, getUrl().getParameter(Constants.SENT_KEY, false)); + send(message, false); } @Override From b08454c827aea9ca5cecc56b39c89e1c3f310995 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Thu, 31 May 2018 09:34:47 +0800 Subject: [PATCH 18/39] add async module to pom for package and bom dependency. --- all/pom.xml | 8 ++++++++ bom/pom.xml | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/all/pom.xml b/all/pom.xml index edc0c4ad7a1..ae00834a199 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -326,6 +326,13 @@ compile true + + com.alibaba + dubbo-async + ${project.version} + compile + true + com.alibaba hessian-lite @@ -426,6 +433,7 @@ com.alibaba:dubbo-serialization-kryo com.alibaba:dubbo-serialization-jdk com.alibaba:dubbo-bootstrap + com.alibaba:dubbo-async diff --git a/bom/pom.xml b/bom/pom.xml index f4d50a9b5d2..0bc5d762176 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -283,6 +283,16 @@ dubbo-serialization-kryo ${project.version} + + com.alibaba + dubbo-bootstrap + ${project.version} + + + com.alibaba + dubbo-async + ${project.version} + com.alibaba hessian-lite From a82db94bacef5fb844bdf07749dbae114dca1785 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 1 Jun 2018 16:34:29 +0800 Subject: [PATCH 19/39] Delete dubbo-async module, it's not necessary. --- all/pom.xml | 8 ----- bom/pom.xml | 5 --- .../dubbo/common/config}/AsyncFor.java | 4 +-- .../alibaba/dubbo/config/ReferenceConfig.java | 2 +- dubbo-plugin/dubbo-async/pom.xml | 35 ------------------- dubbo-plugin/pom.xml | 1 - dubbo-rpc/dubbo-rpc-api/pom.xml | 5 --- .../alibaba/dubbo/rpc/PostProcessFilter.java | 23 ------------ .../alibaba/dubbo/rpc/filter/EchoFilter.java | 10 ++---- .../alibaba/dubbo/rpc/support/RpcUtils.java | 2 +- 10 files changed, 6 insertions(+), 89 deletions(-) rename {dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation => dubbo-common/src/main/java/com/alibaba/dubbo/common/config}/AsyncFor.java (87%) delete mode 100644 dubbo-plugin/dubbo-async/pom.xml delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java diff --git a/all/pom.xml b/all/pom.xml index ae00834a199..edc0c4ad7a1 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -326,13 +326,6 @@ compile true - - com.alibaba - dubbo-async - ${project.version} - compile - true - com.alibaba hessian-lite @@ -433,7 +426,6 @@ com.alibaba:dubbo-serialization-kryo com.alibaba:dubbo-serialization-jdk com.alibaba:dubbo-bootstrap - com.alibaba:dubbo-async diff --git a/bom/pom.xml b/bom/pom.xml index 0bc5d762176..655ded13573 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -288,11 +288,6 @@ dubbo-bootstrap ${project.version} - - com.alibaba - dubbo-async - ${project.version} - com.alibaba hessian-lite diff --git a/dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java similarity index 87% rename from dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java rename to dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java index 58ca6770d1b..fbdee563e59 100644 --- a/dubbo-plugin/dubbo-async/src/main/java/com/alibaba/dubbo/config/annotation/AsyncFor.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.config.annotation; +package com.alibaba.dubbo.common.config; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -23,7 +23,7 @@ import java.lang.annotation.Target; /** - * TODO This definition should placed in module 'dubbo-config-api', but only can be done when "rpc" dependencies are removed from "dubbo-config-api" + * TODO This definition should better be placed in module 'dubbo-config-api', but only can be done when "rpc" dependencies are removed from "dubbo-config-api" * If an interface is annotated with AsyncFor, it will be treated as an async counterpart for the sync one. */ @Documented diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java index 9d5e9dc4e6b..711018d175b 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java @@ -20,12 +20,12 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.Version; import com.alibaba.dubbo.common.bytecode.Wrapper; +import com.alibaba.dubbo.common.config.AsyncFor; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.config.annotation.AsyncFor; import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.model.ApplicationModel; import com.alibaba.dubbo.config.model.ConsumerModel; diff --git a/dubbo-plugin/dubbo-async/pom.xml b/dubbo-plugin/dubbo-async/pom.xml deleted file mode 100644 index bd6f899b7f8..00000000000 --- a/dubbo-plugin/dubbo-async/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - com.alibaba - dubbo-plugin - 2.6.2-SNAPSHOT - - 4.0.0 - - dubbo-async - jar - - dubbo-async - - - UTF-8 - false - - diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml index 36f3229a7d1..ca0e8d94a22 100644 --- a/dubbo-plugin/pom.xml +++ b/dubbo-plugin/pom.xml @@ -30,7 +30,6 @@ The registry module of dubbo project dubbo-qos - dubbo-async false diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index 8e64b02512a..7f08886c147 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -45,10 +45,5 @@ dubbo-remoting-api ${project.parent.version} - - com.alibaba - dubbo-async - ${project.parent.version} - \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java deleted file mode 100644 index f23caf0ca11..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -public interface PostProcessFilter extends Filter { - - void postProcess(Invoker invoker, Invocation invocation, Result result); - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java index d07ae1ce22f..134c496c848 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/EchoFilter.java @@ -18,9 +18,9 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.rpc.Filter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.PostProcessFilter; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcResult; @@ -29,7 +29,7 @@ * EchoInvokerFilter */ @Activate(group = Constants.PROVIDER, order = -110000) -public class EchoFilter implements PostProcessFilter { +public class EchoFilter implements Filter { @Override public Result invoke(Invoker invoker, Invocation inv) throws RpcException { @@ -38,10 +38,4 @@ public Result invoke(Invoker invoker, Invocation inv) throws RpcException { return invoker.invoke(inv); } - @Override - public void postProcess(Invoker invoker, Invocation invocation, Result result) { - System.out.println("Post process for result: " + result.getValue()); - System.out.println("The next invoker in chain is: " + invoker); - - } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java index d23175acd12..6b2a9aa039c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java @@ -18,10 +18,10 @@ import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.config.AsyncFor; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.config.annotation.AsyncFor; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.RpcInvocation; From a79d7f4bab4d16a4600e0621cf2447f541b90eff Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 1 Jun 2018 18:10:18 +0800 Subject: [PATCH 20/39] handle exception throw by provider --- .../main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index 7836a82d32e..f5b7a49de60 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -46,9 +46,10 @@ public void write(Object value) { if (stop()) { if (value instanceof Throwable) { // TODO check exception type like ExceptionFilter do. + Throwable bizExe = (Throwable) value; + future.complete(new RpcResult(bizExe)); } - Result result = new RpcResult(value); - future.complete(result); + future.complete(new RpcResult(value)); } else { throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); } From 39d9a9c1f2324dac62f6207c1daa66cd4b126ef5 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 1 Jun 2018 20:05:37 +0800 Subject: [PATCH 21/39] remove jdk7 support --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e774ec56817..f528526eb07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ sudo: false # faster builds jdk: - oraclejdk9 - oraclejdk8 - - openjdk7 script: - travis_wait 30 mvn clean package From 452638cfd05ce52c2ce911c08d45e85d522f6351 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 13 Jun 2018 17:45:31 +0800 Subject: [PATCH 22/39] support method with original CompletableFuture return type --- .../com/alibaba/dubbo/demo/DemoService.java | 3 + .../alibaba/dubbo/demo/consumer/Consumer.java | 64 ++++++++-- .../META-INF/spring/dubbo-demo-consumer.xml | 2 +- .../dubbo/demo/provider/DemoServiceImpl.java | 6 + .../META-INF/spring/dubbo-demo-provider.xml | 4 +- .../alibaba/dubbo/rpc/AsyncContextImpl.java | 5 +- .../com/alibaba/dubbo/rpc/AsyncResult.java | 76 ++++++++++-- .../com/alibaba/dubbo/rpc/AsyncRpcResult.java | 14 +-- .../alibaba/dubbo/rpc/PostProcessFilter.java | 32 +++++ .../com/alibaba/dubbo/rpc/RpcContext.java | 32 +++-- .../dubbo/rpc/filter/ExceptionFilter.java | 115 ++++++++++-------- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 26 +++- .../rpc/proxy/InvokerInvocationHandler.java | 2 +- .../alibaba/dubbo/rpc/support/RpcUtils.java | 2 +- .../rpc/protocol/dubbo/DubboInvoker.java | 4 +- .../rpc/protocol/dubbo/DubboProtocol.java | 14 --- 16 files changed, 285 insertions(+), 116 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java index 6369c9785a4..2b8e1094534 100644 --- a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java +++ b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java @@ -16,8 +16,11 @@ */ package com.alibaba.dubbo.demo; +import java.util.concurrent.CompletableFuture; + public interface DemoService { String sayHello(String name); + CompletableFuture sayHelloAsync(String name); } \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index d6a83357101..42802bd380d 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -16,14 +16,14 @@ */ package com.alibaba.dubbo.demo.consumer; -import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.rpc.RpcResult; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import java.util.concurrent.CompletableFuture; public class Consumer { - public static void main(String[] args) { - //Prevent to get IPV6 address,this way only work in debug mode + public static void main(String[] args) throws InterruptedException { + /* //Prevent to get IPV6 address,this way only work in debug mode //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); @@ -33,15 +33,65 @@ public static void main(String[] args) { while (true) { try { Thread.sleep(1000); - String hello = demoService.sayHello("world"); // call remote method - System.out.println(hello); // get result + CompletableFuture future = demoService.sayHelloAsync("world"); // call remote method + System.out.println(future.get()); // get result } catch (Throwable throwable) { throwable.printStackTrace(); } - } + }*/ + + + RpcResult resultCreated = new RpcResult(); + CompletableFuture futureCreated = new CompletableFuture(); + futureCreated.whenComplete((Object i, Throwable err) -> { + if (err != null) { + resultCreated.setException(err); + } else { + resultCreated.setValue(i); + } + }); + + RpcResult result = new RpcResult(); + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + throw new RuntimeException("1"); + }).whenComplete((i, err) -> { + if (err != null) { + result.setException(err); + } else { + result.setValue(i); + } + }); + + + future.complete(new RuntimeException("aaa")); + Thread.sleep(500); + System.out.println(result.getException()); + System.out.println(result.getValue()); + + futureCreated.completeExceptionally(new RuntimeException("aaa")); + Thread.sleep(500); + System.out.println(resultCreated.getException()); + System.out.println(resultCreated.getValue()); +// +// try { +//// future.completeExceptionally(new RuntimeException("aaa")); +// +// Object obj =future.get(); +// System.out.println(future.isCompletedExceptionally()); +// System.out.println(obj); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } catch (ExecutionException e) { +// e.printStackTrace(); +// } } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index a3ddebcc2ed..2474d4c92e1 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -26,7 +26,7 @@ - + diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index c5011963977..a3a3c639f84 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -21,6 +21,7 @@ import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.CompletableFuture; public class DemoServiceImpl implements DemoService { @@ -30,4 +31,9 @@ public String sayHello(String name) { return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } + @Override + public CompletableFuture sayHelloAsync(String name) { + return CompletableFuture.completedFuture("CompletableFuture"); + } + } diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index 727954bce02..7db199641c1 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -25,7 +25,7 @@ - + @@ -34,6 +34,6 @@ - + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index f5b7a49de60..0b42cc2a2f9 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -46,10 +46,9 @@ public void write(Object value) { if (stop()) { if (value instanceof Throwable) { // TODO check exception type like ExceptionFilter do. - Throwable bizExe = (Throwable) value; - future.complete(new RpcResult(bizExe)); + future.completeExceptionally((Throwable) value); } - future.complete(new RpcResult(value)); + future.complete(value); } else { throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java index 015c52c2645..6740e8bc6c0 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java @@ -16,45 +16,105 @@ */ package com.alibaba.dubbo.rpc; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; /** * */ -public abstract class AsyncResult implements Result { +public abstract class AsyncResult implements Result { + private static final Logger logger = LoggerFactory.getLogger(AsyncResult.class); + + protected CompletableFuture valueFuture; + + protected CompletableFuture resultFuture; + + // TODO remove + protected Result rpcResult; + + protected AsyncResult(CompletableFuture future) { + this(future, true); + } + + protected AsyncResult(CompletableFuture future, boolean registerCallback) { + if (registerCallback) { + resultFuture = new CompletableFuture<>(); + future.whenComplete((v, t) -> { + if (t != null) { + if (t instanceof CompletionException) { + rpcResult = new RpcResult(t.getCause()); + } else { + rpcResult = new RpcResult(t); + } + } else { + rpcResult = new RpcResult(v); + } + resultFuture.complete(rpcResult); + }); + } + this.valueFuture = future; + } @Override public Object getValue() { - return null; + return rpcResult.getValue(); } @Override public Throwable getException() { - return null; + return rpcResult.getException(); } @Override public boolean hasException() { - return false; + return rpcResult.hasException(); } @Override public Object getResult() { - return null; + return rpcResult.getResult(); } @Override public Map getAttachments() { - return null; + return rpcResult.getAttachments(); } @Override public String getAttachment(String key) { - return null; + return rpcResult.getAttachment(key); } @Override public String getAttachment(String key, String defaultValue) { - return null; + return rpcResult.getAttachment(key, defaultValue); + } + + public CompletableFuture getValueFuture() { + return valueFuture; + } + + public CompletableFuture getResultFuture() { + return resultFuture; + } + + public void setResultFuture(CompletableFuture resultFuture) { + this.resultFuture = resultFuture; + } + + public Result getRpcResult() { + Result result; + try { + result = resultFuture.get(); + } catch (Exception e) { + // This should never happen; + logger.error("", e); + result = new RpcResult(); + } + return result; } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java index 47b4166cfff..bc3375764b4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java @@ -21,20 +21,18 @@ /** * */ -public class AsyncRpcResult extends AsyncResult { +public class AsyncRpcResult extends AsyncResult { - private CompletableFuture future; - - public AsyncRpcResult(CompletableFuture future) { - this.future = future; + public AsyncRpcResult(CompletableFuture future) { + super(future); } - public CompletableFuture getFuture() { - return future; + public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { + super(future, registerCallback); } @Override public Object recreate() throws Throwable { - return future; + return valueFuture; } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java new file mode 100644 index 00000000000..e6475277f69 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +/** + * + */ +public interface PostProcessFilter extends Filter { + /** + * TODO Filter is singleton, so we have to add invoker & invocation as parameters for every invoke. + * + * @param result + * @param invoker + * @param invocation + * @return + */ + Result postProcessResult(Result result, Invoker invoker, Invocation invocation); +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java index 560bb695078..a2fda8d16b2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -108,23 +108,6 @@ public static void removeContext() { LOCAL.remove(); } - /** - * TODO call multiple times in different thread? - * - * @return - * @throws IllegalStateException - */ - @SuppressWarnings("unchecked") - public static AsyncContext startAsync() throws IllegalStateException { - RpcContext currentContext = getContext(); - if (currentContext.asyncContext != null) { - currentContext.asyncContext.start(); - return currentContext.asyncContext; - } else { - throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); - } - } - /** * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest * @@ -685,6 +668,21 @@ public void asyncCall(Runnable runnable) { } } + /** + * @return + * @throws IllegalStateException + */ + @SuppressWarnings("unchecked") + public static AsyncContext startAsync() throws IllegalStateException { + RpcContext currentContext = getContext(); + if (currentContext.asyncContext != null) { + currentContext.asyncContext.start(); + return currentContext.asyncContext; + } else { + throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); + } + } + public boolean isAsyncStarted() { if (this.asyncContext == null) { return false; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java index 40b8046466c..d852c68c8de 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java @@ -22,9 +22,10 @@ import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.AsyncResult; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.PostProcessFilter; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; @@ -32,6 +33,7 @@ import com.alibaba.dubbo.rpc.service.GenericService; import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; /** * ExceptionInvokerFilter @@ -44,7 +46,7 @@ * */ @Activate(group = Constants.PROVIDER) -public class ExceptionFilter implements Filter { +public class ExceptionFilter implements PostProcessFilter { private final Logger logger; @@ -60,64 +62,75 @@ public ExceptionFilter(Logger logger) { public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { try { Result result = invoker.invoke(invocation); - if (result.hasException() && GenericService.class != invoker.getInterface()) { - try { - Throwable exception = result.getException(); + if (result instanceof AsyncResult) { + AsyncResult asyncResultesult = (AsyncResult) result; + CompletableFuture future = asyncResultesult.getResultFuture(); + asyncResultesult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); + return asyncResultesult; + } else { + return postProcessResult(result, invoker, 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; + } + } - // 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 - 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; - } + public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { + if (result.hasException() && GenericService.class != invoker.getInterface()) { + try { + Throwable exception = result.getException(); + + // 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 + 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; } - } catch (NoSuchMethodException e) { - return result; } + } 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); - - // 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; - } + // 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); - // 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); + // 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; + } + + // 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; } - return result; - } 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 result; } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java index 26dfdafb013..7c51848919d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -17,13 +17,18 @@ package com.alibaba.dubbo.rpc.proxy; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.AsyncContextImpl; +import com.alibaba.dubbo.rpc.AsyncRpcResult; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcResult; +import com.alibaba.dubbo.rpc.support.RpcUtils; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CompletableFuture; /** * InvokerWrapper @@ -70,11 +75,30 @@ public boolean isAvailable() { public void destroy() { } + // TODO Unified to AsyncResult? @Override public Result invoke(Invocation invocation) throws RpcException { try { - return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments())); + RpcContext rpcContext = RpcContext.getContext(); + if (RpcUtils.isAsyncFuture(null, invocation)) { + CompletableFuture future = new CompletableFuture<>(); + rpcContext.setAsyncContext(new AsyncContextImpl(future)); + Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); + // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. + if (rpcContext.isAsyncStarted()) { + return new AsyncRpcResult(future); + } else { + return new RpcResult(obj); + } + } else { + Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); + if (obj instanceof CompletableFuture) { + return new AsyncRpcResult((CompletableFuture) obj); + } + return new RpcResult(obj); + } } catch (InvocationTargetException e) { + // TODO async throw exception before async thread write back, should stop asyncContext return new RpcResult(e.getTargetException()); } catch (Throwable e) { throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java index 488f6ca2518..2f6a354804f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java @@ -53,7 +53,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } RpcInvocation invocation; - if (RpcUtils.isAsyncFuture(method)) { + if (RpcUtils.isGeneratedAsyncFuture(method)) { Class clazz = method.getDeclaringClass(); String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes()); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java index 6b2a9aa039c..b0a2411e2af 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java @@ -161,7 +161,7 @@ public static boolean isAsyncFuture(URL url, Invocation inv) { return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_KEY)); } - public static boolean isAsyncFuture(Method method) { + public static boolean isGeneratedAsyncFuture(Method method) { Class clazz = method.getDeclaringClass(); return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 1aabb943cf0..32db90dd401 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -89,11 +89,11 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { return new RpcResult(); } else if (isAsync) { ResponseFuture future = currentClient.request(inv, timeout); - FutureAdapter futureAdapter = new FutureAdapter<>(future); + FutureAdapter futureAdapter = new FutureAdapter<>(future); RpcContext.getContext().setFuture(futureAdapter); Result result; if (RpcUtils.isAsyncFuture(getUrl(), inv)) { - result = new AsyncRpcResult<>(futureAdapter); + result = new AsyncRpcResult(futureAdapter, false); } else { result = new RpcResult(); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 01411730d41..82d4fc3f690 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -34,7 +34,6 @@ import com.alibaba.dubbo.remoting.exchange.ExchangeServer; import com.alibaba.dubbo.remoting.exchange.Exchangers; import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import com.alibaba.dubbo.rpc.AsyncContextImpl; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -102,23 +101,10 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) return null; } } - boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); - CompletableFuture resultFuture = new CompletableFuture<>(); RpcContext rpcContext = RpcContext.getContext(); - if (supportServerAsync) { - rpcContext.setAsyncContext(new AsyncContextImpl(resultFuture)); - } rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); - if (!rpcContext.isAsyncStarted()) { - resultFuture.complete(result); - } else if (rpcContext.isAsyncStarted() && result.hasException()) { - if (rpcContext.stopAsync()) { - resultFuture.complete(result); - } - } - return resultFuture; } throw new RemotingException(channel, "Unsupported request: " + (message == null ? null : (message.getClass().getName() + ": " + message)) From d65835f30c2e833dfe9f8be40eaadfffd0c2e3dc Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Thu, 14 Jun 2018 16:14:01 +0800 Subject: [PATCH 23/39] support method with original future return type. --- .../com/alibaba/dubbo/common/Constants.java | 3 +- .../com/alibaba/dubbo/rpc/AsyncContext.java | 4 ++ .../alibaba/dubbo/rpc/AsyncContextImpl.java | 5 +++ .../com/alibaba/dubbo/rpc/AsyncResult.java | 18 ++++---- .../com/alibaba/dubbo/rpc/RpcContext.java | 4 ++ .../dubbo/rpc/filter/ExceptionFilter.java | 8 ++-- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 21 +++------- .../rpc/proxy/InvokerInvocationHandler.java | 8 +++- .../alibaba/dubbo/rpc/support/RpcUtils.java | 41 ++++++++++++++++--- .../dubbo/rpc/protocol/dubbo/DubboCodec.java | 3 +- .../rpc/protocol/dubbo/DubboInvoker.java | 3 +- .../rpc/protocol/dubbo/DubboProtocol.java | 12 ++++++ 12 files changed, 90 insertions(+), 40 deletions(-) diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java index 23856317c87..9e4fd3d5288 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -281,7 +281,8 @@ public class Constants { public static final String ASYNC_KEY = "async"; - public static final String FUTURE_KEY = "async_future"; + public static final String FUTURE_GENERATED_KEY = "future_generated"; + public static final String FUTURE_RETURNTYPE_KEY = "future_returntype"; public static final String ASYNC_SUFFIX = "Async"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java index f5e4e5cb15c..6b418c52bf6 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java @@ -16,8 +16,12 @@ */ package com.alibaba.dubbo.rpc; +import java.util.concurrent.CompletableFuture; + public interface AsyncContext { + CompletableFuture getInternalFuture(); + void addListener(Runnable run); void write(Object value); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index 0b42cc2a2f9..bf8d9038580 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -72,4 +72,9 @@ public boolean stop() { public void start() { this.started.set(true); } + + @Override + public CompletableFuture getInternalFuture() { + return future; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java index 6740e8bc6c0..d1cd9e79ab1 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java @@ -33,9 +33,6 @@ public abstract class AsyncResult implements Result { protected CompletableFuture resultFuture; - // TODO remove - protected Result rpcResult; - protected AsyncResult(CompletableFuture future) { this(future, true); } @@ -44,6 +41,7 @@ protected AsyncResult(CompletableFuture future, boolean registerCallback if (registerCallback) { resultFuture = new CompletableFuture<>(); future.whenComplete((v, t) -> { + RpcResult rpcResult; if (t != null) { if (t instanceof CompletionException) { rpcResult = new RpcResult(t.getCause()); @@ -61,37 +59,37 @@ protected AsyncResult(CompletableFuture future, boolean registerCallback @Override public Object getValue() { - return rpcResult.getValue(); + return getRpcResult().getValue(); } @Override public Throwable getException() { - return rpcResult.getException(); + return getRpcResult().getException(); } @Override public boolean hasException() { - return rpcResult.hasException(); + return getRpcResult().hasException(); } @Override public Object getResult() { - return rpcResult.getResult(); + return getRpcResult().getResult(); } @Override public Map getAttachments() { - return rpcResult.getAttachments(); + return getRpcResult().getAttachments(); } @Override public String getAttachment(String key) { - return rpcResult.getAttachment(key); + return getRpcResult().getAttachment(key); } @Override public String getAttachment(String key, String defaultValue) { - return rpcResult.getAttachment(key, defaultValue); + return getRpcResult().getAttachment(key, defaultValue); } public CompletableFuture getValueFuture() { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java index a2fda8d16b2..f1a294ea2f2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java @@ -699,4 +699,8 @@ public boolean stopAsync() { public void setAsyncContext(AsyncContext asyncContext) { this.asyncContext = asyncContext; } + + public AsyncContext getAsyncContext() { + return asyncContext; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java index d852c68c8de..ae160e5ac5c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java @@ -63,10 +63,10 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept try { Result result = invoker.invoke(invocation); if (result instanceof AsyncResult) { - AsyncResult asyncResultesult = (AsyncResult) result; - CompletableFuture future = asyncResultesult.getResultFuture(); - asyncResultesult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); - return asyncResultesult; + AsyncResult asyncResult = (AsyncResult) result; + CompletableFuture future = asyncResult.getResultFuture(); + asyncResult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); + return asyncResult; } else { return postProcessResult(result, invoker, invocation); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java index 7c51848919d..c1cbd3c6988 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -17,7 +17,6 @@ package com.alibaba.dubbo.rpc.proxy; import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.AsyncContextImpl; import com.alibaba.dubbo.rpc.AsyncRpcResult; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -79,22 +78,12 @@ public void destroy() { @Override public Result invoke(Invocation invocation) throws RpcException { try { - RpcContext rpcContext = RpcContext.getContext(); - if (RpcUtils.isAsyncFuture(null, invocation)) { - CompletableFuture future = new CompletableFuture<>(); - rpcContext.setAsyncContext(new AsyncContextImpl(future)); - Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); - // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. - if (rpcContext.isAsyncStarted()) { - return new AsyncRpcResult(future); - } else { - return new RpcResult(obj); - } + Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); + if (RpcUtils.isFutureReturnType(invocation)) { + return new AsyncRpcResult((CompletableFuture) obj); + } else if (RpcContext.getContext().isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. + return new AsyncRpcResult(RpcContext.getContext().getAsyncContext().getInternalFuture()); } else { - Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); - if (obj instanceof CompletableFuture) { - return new AsyncRpcResult((CompletableFuture) obj); - } return new RpcResult(obj); } } catch (InvocationTargetException e) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java index 2f6a354804f..7e7cc4e60bd 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java @@ -53,15 +53,19 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } RpcInvocation invocation; - if (RpcUtils.isGeneratedAsyncFuture(method)) { + if (RpcUtils.hasGeneratedFuture(method)) { Class clazz = method.getDeclaringClass(); String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes()); invocation = new RpcInvocation(syncMethod, args); - invocation.setAttachment(Constants.FUTURE_KEY, "true"); + invocation.setAttachment(Constants.FUTURE_GENERATED_KEY, "true"); invocation.setAttachment(Constants.ASYNC_KEY, "true"); } else { invocation = new RpcInvocation(method, args); + if (RpcUtils.hasFutureReturnType(method)) { + invocation.setAttachment(Constants.FUTURE_RETURNTYPE_KEY, "true"); + invocation.setAttachment(Constants.ASYNC_KEY, "true"); + } } return invoker.invoke(invocation).recreate(); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java index b0a2411e2af..c0db9edfc4b 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java @@ -26,8 +26,11 @@ import com.alibaba.dubbo.rpc.RpcInvocation; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; /** @@ -59,6 +62,7 @@ public static Class getReturnType(Invocation invocation) { return null; } + // TODO why not get return type when initialize Invocation? public static Type[] getReturnTypes(Invocation invocation) { try { if (invocation != null && invocation.getInvoker() != null @@ -71,7 +75,17 @@ public static Type[] getReturnTypes(Invocation invocation) { if (method.getReturnType() == void.class) { return null; } - return new Type[]{method.getReturnType(), method.getGenericReturnType()}; + Class returnType = method.getReturnType(); + Type genericReturnType = method.getGenericReturnType(); + if (Future.class.isAssignableFrom(returnType)) { + if (genericReturnType instanceof ParameterizedType) { + returnType = (Class) ((ParameterizedType) genericReturnType).getActualTypeArguments()[0]; + } + genericReturnType = returnType; // TODO Can we handle nested generic? for example CompletableFuture> + } else { + genericReturnType = returnType; + } + return new Type[]{returnType, genericReturnType}; } } } catch (Throwable t) { @@ -157,13 +171,21 @@ public static boolean isAsync(URL url, Invocation inv) { return isAsync; } - public static boolean isAsyncFuture(URL url, Invocation inv) { - return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_KEY)); + public static boolean isGeneratedFuture(Invocation inv) { + return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_GENERATED_KEY)); } - public static boolean isGeneratedAsyncFuture(Method method) { + public static boolean hasGeneratedFuture(Method method) { Class clazz = method.getDeclaringClass(); - return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class); + return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && hasFutureReturnType(method); + } + + public static boolean isFutureReturnType(Invocation inv) { + return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_RETURNTYPE_KEY)); + } + + public static boolean hasFutureReturnType(Method method) { + return CompletableFuture.class.isAssignableFrom(method.getReturnType()); } public static boolean isOneway(URL url, Invocation inv) { @@ -176,4 +198,13 @@ public static boolean isOneway(URL url, Invocation inv) { return isOneway; } + public static Map getNecessaryAttachments(Invocation inv) { + Map attachments = inv.getAttachments(); + if (attachments != null) { + attachments.remove(Constants.ASYNC_KEY); + attachments.remove(Constants.FUTURE_GENERATED_KEY); + } + return attachments; + } + } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java index 8c633f79166..5b7fcbfe71b 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java @@ -37,6 +37,7 @@ import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.support.RpcUtils; import java.io.IOException; import java.io.InputStream; @@ -175,7 +176,7 @@ protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) for (int i = 0; i < args.length; i++) { out.writeObject(encodeInvocationArgument(channel, inv, i)); } - out.writeObject(inv.getAttachments()); + out.writeObject(RpcUtils.getNecessaryAttachments(inv)); } @Override diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 32db90dd401..cd7c45dbf95 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -80,6 +80,7 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { } try { boolean isAsync = RpcUtils.isAsync(getUrl(), invocation); + boolean isAsyncFuture = RpcUtils.isGeneratedFuture(inv) || RpcUtils.isFutureReturnType(inv); boolean isOneway = RpcUtils.isOneway(getUrl(), invocation); int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); if (isOneway) { @@ -92,7 +93,7 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { FutureAdapter futureAdapter = new FutureAdapter<>(future); RpcContext.getContext().setFuture(futureAdapter); Result result; - if (RpcUtils.isAsyncFuture(getUrl(), inv)) { + if (isAsyncFuture) { result = new AsyncRpcResult(futureAdapter, false); } else { result = new RpcResult(); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 82d4fc3f690..b4946138a77 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -34,6 +34,8 @@ import com.alibaba.dubbo.remoting.exchange.ExchangeServer; import com.alibaba.dubbo.remoting.exchange.Exchangers; import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; +import com.alibaba.dubbo.rpc.AsyncContextImpl; +import com.alibaba.dubbo.rpc.AsyncResult; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -102,9 +104,19 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) } } RpcContext rpcContext = RpcContext.getContext(); + boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); + if (supportServerAsync) { + CompletableFuture future = new CompletableFuture<>(); + rpcContext.setAsyncContext(new AsyncContextImpl(future)); + } rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); + if (result instanceof AsyncResult) { + return ((AsyncResult) result).getResultFuture().thenApply(r -> (Object) r); + } else { + return CompletableFuture.completedFuture(result); + } } throw new RemotingException(channel, "Unsupported request: " + (message == null ? null : (message.getClass().getName() + ": " + message)) From 0a81d5c09166479e52ef0b259c28d75f1e058d1b Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Thu, 14 Jun 2018 16:19:40 +0800 Subject: [PATCH 24/39] demo test --- dubbo-demo/dubbo-demo-api/pom.xml | 7 ++ .../com/alibaba/dubbo/demo/DemoService.java | 2 +- .../alibaba/dubbo/demo/DemoServiceAsync.java | 29 ++++++++ .../alibaba/dubbo/demo/consumer/Consumer.java | 70 ++++--------------- .../META-INF/spring/dubbo-demo-consumer.xml | 2 + .../dubbo/demo/provider/DemoServiceImpl.java | 27 ++++++- .../META-INF/spring/dubbo-demo-provider.xml | 2 +- 7 files changed, 78 insertions(+), 61 deletions(-) create mode 100644 dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index a9179b55034..84c2ee97ee6 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -28,4 +28,11 @@ true + + + + com.alibaba + dubbo-common + + \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java index 2b8e1094534..a00d8e57fdb 100644 --- a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java +++ b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java @@ -22,5 +22,5 @@ public interface DemoService { String sayHello(String name); - CompletableFuture sayHelloAsync(String name); + CompletableFuture originalFuture(String name); } \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java new file mode 100644 index 00000000000..7325a6086f8 --- /dev/null +++ b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.demo; + +import com.alibaba.dubbo.common.config.AsyncFor; + +import java.util.concurrent.CompletableFuture; + +/** + * + */ +@AsyncFor(DemoService.class) +public interface DemoServiceAsync extends DemoService { + CompletableFuture sayHelloAsync(String name); +} diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index 42802bd380d..3fcfffb81a6 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -16,82 +16,38 @@ */ package com.alibaba.dubbo.demo.consumer; +import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.demo.DemoServiceAsync; import com.alibaba.dubbo.rpc.RpcResult; +import org.springframework.context.support.ClassPathXmlApplicationContext; + import java.util.concurrent.CompletableFuture; public class Consumer { public static void main(String[] args) throws InterruptedException { - /* //Prevent to get IPV6 address,this way only work in debug mode + //Prevent to get IPV6 address,this way only work in debug mode //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy + DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoServiceAsync"); while (true) { try { - Thread.sleep(1000); - CompletableFuture future = demoService.sayHelloAsync("world"); // call remote method + CompletableFuture future = demoService.originalFuture("world"); // call remote method System.out.println(future.get()); // get result + System.out.println(demoService.sayHello("world")); + + CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); + System.out.println(generatedFuture.get()); + Thread.sleep(1000); } catch (Throwable throwable) { throwable.printStackTrace(); } - - - }*/ - - - RpcResult resultCreated = new RpcResult(); - CompletableFuture futureCreated = new CompletableFuture(); - futureCreated.whenComplete((Object i, Throwable err) -> { - if (err != null) { - resultCreated.setException(err); - } else { - resultCreated.setValue(i); - } - }); - - RpcResult result = new RpcResult(); - CompletableFuture future = CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - throw new RuntimeException("1"); - }).whenComplete((i, err) -> { - if (err != null) { - result.setException(err); - } else { - result.setValue(i); - } - }); - - - future.complete(new RuntimeException("aaa")); - Thread.sleep(500); - System.out.println(result.getException()); - System.out.println(result.getValue()); - - futureCreated.completeExceptionally(new RuntimeException("aaa")); - Thread.sleep(500); - System.out.println(resultCreated.getException()); - System.out.println(resultCreated.getValue()); -// -// try { -//// future.completeExceptionally(new RuntimeException("aaa")); -// -// Object obj =future.get(); -// System.out.println(future.isCompletedExceptionally()); -// System.out.println(obj); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } catch (ExecutionException e) { -// e.printStackTrace(); -// } - + } } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index 2474d4c92e1..8f12396b52e 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -32,4 +32,6 @@ local regular interface --> + + \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index a3a3c639f84..9efe809c635 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -17,6 +17,7 @@ package com.alibaba.dubbo.demo.provider; import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.rpc.AsyncContext; import com.alibaba.dubbo.rpc.RpcContext; import java.text.SimpleDateFormat; @@ -28,12 +29,34 @@ public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + startAsync(name); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } @Override - public CompletableFuture sayHelloAsync(String name) { - return CompletableFuture.completedFuture("CompletableFuture"); + public CompletableFuture originalFuture(String name) { + return CompletableFuture.supplyAsync(() ->{ + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "test Async"; + }); + } + + private void startAsync(String name) { + AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + System.out.println(" -- Async start."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from async provider."); + System.out.println(" -- Async end."); + }).start(); } } diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index 7db199641c1..b696a07a39e 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -34,6 +34,6 @@ - + \ No newline at end of file From a9ca1013c3f516719f068f5244cf8ee630eba68a Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 15 Jun 2018 14:06:36 +0800 Subject: [PATCH 25/39] optimization --- .../support/header/HeaderExchangeHandler.java | 2 +- .../com/alibaba/dubbo/rpc/AbstractResult.java | 71 +++++++++++ .../com/alibaba/dubbo/rpc/AsyncContext.java | 2 + .../alibaba/dubbo/rpc/AsyncContextImpl.java | 5 + .../com/alibaba/dubbo/rpc/AsyncResult.java | 118 ------------------ .../com/alibaba/dubbo/rpc/AsyncRpcResult.java | 84 ++++++++++++- .../java/com/alibaba/dubbo/rpc/Result.java | 17 ++- .../java/com/alibaba/dubbo/rpc/RpcResult.java | 54 +------- .../rpc/filter/ConsumerContextFilter.java | 3 +- .../dubbo/rpc/filter/ContextFilter.java | 3 +- .../dubbo/rpc/filter/ExceptionFilter.java | 6 +- .../alibaba/dubbo/rpc/support/RpcUtils.java | 9 +- .../rpc/protocol/dubbo/DubboInvoker.java | 3 +- .../rpc/protocol/dubbo/DubboProtocol.java | 6 +- 14 files changed, 191 insertions(+), 192 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java index a025ccd61fe..81139bc68a1 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -102,7 +102,7 @@ void handleRequest(ExchangeChannel channel, Request req) throws RemotingExceptio channel.send(res); return; } - future.whenCompleteAsync((result, t) -> { + future.whenComplete((result, t) -> { try { if (t == null) { res.setStatus(Response.OK); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java new file mode 100644 index 00000000000..aa63115cc62 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.rpc; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public abstract class AbstractResult implements Result { + protected Map attachments = new HashMap(); + + protected Object result; + + protected Throwable exception; + + @Override + public Map getAttachments() { + return attachments; + } + + @Override + public void setAttachments(Map map) { + this.attachments = map == null ? new HashMap() : map; + } + + @Override + public void addAttachments(Map map) { + if (map == null) { + return; + } + if (this.attachments == null) { + this.attachments = new HashMap(); + } + 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); + } + +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java index 6b418c52bf6..ae5671ee11d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java @@ -31,4 +31,6 @@ public interface AsyncContext { boolean stop(); void start(); + + void signalContextSwitch(); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java index bf8d9038580..2b360e69be1 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java @@ -73,6 +73,11 @@ public void start() { this.started.set(true); } + @Override + public void signalContextSwitch() { + + } + @Override public CompletableFuture getInternalFuture() { return future; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java deleted file mode 100644 index d1cd9e79ab1..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncResult.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; - -/** - * - */ -public abstract class AsyncResult implements Result { - private static final Logger logger = LoggerFactory.getLogger(AsyncResult.class); - - protected CompletableFuture valueFuture; - - protected CompletableFuture resultFuture; - - protected AsyncResult(CompletableFuture future) { - this(future, true); - } - - protected AsyncResult(CompletableFuture future, boolean registerCallback) { - if (registerCallback) { - resultFuture = new CompletableFuture<>(); - 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); - } - resultFuture.complete(rpcResult); - }); - } - this.valueFuture = future; - } - - @Override - public Object getValue() { - return getRpcResult().getValue(); - } - - @Override - public Throwable getException() { - return getRpcResult().getException(); - } - - @Override - public boolean hasException() { - return getRpcResult().hasException(); - } - - @Override - public Object getResult() { - return getRpcResult().getResult(); - } - - @Override - public Map getAttachments() { - return getRpcResult().getAttachments(); - } - - @Override - public String getAttachment(String key) { - return getRpcResult().getAttachment(key); - } - - @Override - public String getAttachment(String key, String defaultValue) { - return getRpcResult().getAttachment(key, defaultValue); - } - - public CompletableFuture getValueFuture() { - return valueFuture; - } - - public CompletableFuture getResultFuture() { - return resultFuture; - } - - public void setResultFuture(CompletableFuture resultFuture) { - this.resultFuture = resultFuture; - } - - public Result getRpcResult() { - Result result; - try { - result = resultFuture.get(); - } catch (Exception e) { - // This should never happen; - logger.error("", e); - result = new RpcResult(); - } - return result; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java index bc3375764b4..9390da5b014 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java @@ -16,19 +16,97 @@ */ package com.alibaba.dubbo.rpc; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; /** * */ -public class AsyncRpcResult extends AsyncResult { +public class AsyncRpcResult extends AbstractResult { + private static final Logger logger = LoggerFactory.getLogger(AsyncRpcResult.class); + + private Map attachments = new HashMap(); + + protected CompletableFuture valueFuture; + + protected CompletableFuture resultFuture; public AsyncRpcResult(CompletableFuture future) { - super(future); + this(future, true); } public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { - super(future, registerCallback); + if (registerCallback) { + resultFuture = new CompletableFuture<>(); + /** + * 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, is Dubbo thread. + * 2. future complete after whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread calling complete, normally is 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); + } + resultFuture.complete(rpcResult); + }); + } + this.valueFuture = future; + } + + @Override + public Object getValue() { + return getRpcResult().getValue(); + } + + @Override + public Throwable getException() { + return getRpcResult().getException(); + } + + @Override + public boolean hasException() { + return getRpcResult().hasException(); + } + + @Override + public Object getResult() { + return getRpcResult().getResult(); + } + + public CompletableFuture getValueFuture() { + return valueFuture; + } + + public CompletableFuture getResultFuture() { + return resultFuture; + } + + public void setResultFuture(CompletableFuture resultFuture) { + this.resultFuture = resultFuture; + } + + public Result getRpcResult() { + Result result; + try { + result = resultFuture.get(); + } catch (Exception e) { + // This should never happen; + logger.error("", e); + result = new RpcResult(); + } + return result; } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java index 6a74b2b906a..a1858e7dfee 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java @@ -16,6 +16,7 @@ */ package com.alibaba.dubbo.rpc; +import java.io.Serializable; import java.util.Map; /** @@ -25,7 +26,7 @@ * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation) * @see com.alibaba.dubbo.rpc.RpcResult */ -public interface Result { +public interface Result extends Serializable { /** * Get invoke result. @@ -79,6 +80,20 @@ public interface Result { */ Map getAttachments(); + /** + * Add the specified map to existing attachments in this instance. + * + * @param map + */ + public void addAttachments(Map map); + + /** + * Replace the existing attachments with the specified param. + * + * @param map + */ + public void setAttachments(Map map); + /** * get attachment by key. * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java index 8d3811bde40..699a7d0a52f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java @@ -16,25 +16,15 @@ */ package com.alibaba.dubbo.rpc; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - /** * RPC Result. * * @serial Don't change the class name and properties. */ -public class RpcResult implements Result, Serializable { +public class RpcResult extends AbstractResult { private static final long serialVersionUID = -6925924956850004727L; - private Object result; - - private Throwable exception; - - private Map attachments = new HashMap(); - public RpcResult() { } @@ -96,48 +86,6 @@ public boolean hasException() { return exception != null; } - @Override - public Map 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 map) { - this.attachments = map == null ? new HashMap() : map; - } - - public void addAttachments(Map map) { - if (map == null) { - return; - } - if (this.attachments == null) { - this.attachments = new HashMap(); - } - 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 String toString() { return "RpcResult [result=" + result + ", exception=" + exception + "]"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java index 8c9f822d7fd..3c1b5e4a38c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java @@ -26,7 +26,6 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.RpcResult; /** * ConsumerContextInvokerFilter @@ -46,7 +45,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - RpcResult result = (RpcResult) invoker.invoke(invocation); + Result result = invoker.invoke(invocation); RpcContext.getServerContext().setAttachments(result.getAttachments()); return result; } finally { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java index f423349260a..82c43905df0 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java @@ -25,7 +25,6 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.RpcResult; import java.util.HashMap; import java.util.Map; @@ -70,7 +69,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - RpcResult result = (RpcResult) invoker.invoke(invocation); + Result result = invoker.invoke(invocation); // pass attachments to result result.addAttachments(RpcContext.getServerContext().getAttachments()); return result; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java index ae160e5ac5c..8c7446fe590 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java @@ -22,7 +22,7 @@ import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.rpc.AsyncResult; +import com.alibaba.dubbo.rpc.AsyncRpcResult; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.PostProcessFilter; @@ -62,8 +62,8 @@ public ExceptionFilter(Logger logger) { public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { try { Result result = invoker.invoke(invocation); - if (result instanceof AsyncResult) { - AsyncResult asyncResult = (AsyncResult) result; + if (result instanceof AsyncRpcResult) { + AsyncRpcResult asyncResult = (AsyncRpcResult) result; CompletableFuture future = asyncResult.getResultFuture(); asyncResult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); return asyncResult; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java index c0db9edfc4b..6930b22f70a 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java @@ -28,6 +28,7 @@ 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; @@ -199,11 +200,9 @@ public static boolean isOneway(URL url, Invocation inv) { } public static Map getNecessaryAttachments(Invocation inv) { - Map attachments = inv.getAttachments(); - if (attachments != null) { - attachments.remove(Constants.ASYNC_KEY); - attachments.remove(Constants.FUTURE_GENERATED_KEY); - } + Map attachments = new HashMap<>(inv.getAttachments()); + attachments.remove(Constants.ASYNC_KEY); + attachments.remove(Constants.FUTURE_GENERATED_KEY); return attachments; } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index cd7c45dbf95..2ac8347bc48 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -94,7 +94,8 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { RpcContext.getContext().setFuture(futureAdapter); Result result; if (isAsyncFuture) { - result = new AsyncRpcResult(futureAdapter, false); + // register resultCallback, sometimes we need the result being processed in the filter chain. + result = new AsyncRpcResult(futureAdapter, true); } else { result = new RpcResult(); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 75619564f91..ae362741e14 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -35,7 +35,7 @@ import com.alibaba.dubbo.remoting.exchange.Exchangers; import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; import com.alibaba.dubbo.rpc.AsyncContextImpl; -import com.alibaba.dubbo.rpc.AsyncResult; +import com.alibaba.dubbo.rpc.AsyncRpcResult; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; @@ -113,8 +113,8 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); - if (result instanceof AsyncResult) { - return ((AsyncResult) result).getResultFuture().thenApply(r -> (Object) r); + if (result instanceof AsyncRpcResult) { + return ((AsyncRpcResult) result).getResultFuture().thenApply(r -> (Object) r); } else { return CompletableFuture.completedFuture(result); } From 2b3b2cfbcbc35d040187665bb8b3537c6b009c7f Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 15 Jun 2018 14:06:59 +0800 Subject: [PATCH 26/39] test biz exception --- .../alibaba/dubbo/demo/consumer/Consumer.java | 22 ++++++++++++------- .../dubbo/demo/provider/DemoServiceImpl.java | 6 +++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java index 3fcfffb81a6..0f5c32582ee 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java @@ -18,7 +18,6 @@ import com.alibaba.dubbo.demo.DemoService; import com.alibaba.dubbo.demo.DemoServiceAsync; -import com.alibaba.dubbo.rpc.RpcResult; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -37,13 +36,20 @@ public static void main(String[] args) throws InterruptedException { while (true) { try { - CompletableFuture future = demoService.originalFuture("world"); // call remote method - System.out.println(future.get()); // get result - - System.out.println(demoService.sayHello("world")); - - CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); - System.out.println(generatedFuture.get()); + try { + CompletableFuture future = demoService.originalFuture("world"); // call remote method + System.out.println(future.get()); // get result + } catch (Exception e) { + e.printStackTrace(); + } + +// System.out.println(demoService.sayHello("world")); + try { + CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); + System.out.println(generatedFuture.get()); + } catch (Exception e) { + e.printStackTrace(); + } Thread.sleep(1000); } catch (Throwable throwable) { throwable.printStackTrace(); diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java index 9efe809c635..b9d01001751 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java @@ -30,7 +30,8 @@ public class DemoServiceImpl implements DemoService { public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); startAsync(name); - return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); + throw new RuntimeException("bbb"); +// return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } @Override @@ -41,7 +42,8 @@ public CompletableFuture originalFuture(String name) { } catch (InterruptedException e) { e.printStackTrace(); } - return "test Async"; + throw new RuntimeException("aaa"); +// return "test Async"; }); } From bae63ea1505d71b4ff022e745d9b634e27e3d797 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Fri, 15 Jun 2018 15:38:34 +0800 Subject: [PATCH 27/39] Manually resolve conflicts after merge master(repackage) --- .../rpc/cluster/support/ClusterUtils.java | 112 --- .../com/alibaba/dubbo/common/Constants.java | 649 ---------------- .../alibaba/dubbo/common/config/AsyncFor.java | 41 - .../org/apache/dubbo/common/Constants.java | 4 +- .../apache/dubbo/common/config/AsyncFor.java | 1 + .../alibaba/dubbo/config/ReferenceConfig.java | 562 -------------- .../com/alibaba/dubbo/demo/DemoService.java | 26 - .../org/apache/dubbo/demo/DemoService.java | 3 + .../apache}/dubbo/demo/DemoServiceAsync.java | 4 +- .../alibaba/dubbo/demo/consumer/Consumer.java | 59 -- .../apache/dubbo/demo/consumer/Consumer.java | 27 +- .../META-INF/spring/dubbo-demo-consumer.xml | 2 +- .../dubbo/demo/provider/DemoServiceImpl.java | 64 -- .../dubbo/demo/provider/DemoServiceImpl.java | 33 + .../META-INF/spring/dubbo-demo-provider.xml | 4 +- .../integration/RegistryProtocol.java | 520 ------------- .../remoting/exchange/ExchangeHandler.java | 40 - .../support/ExchangeHandlerAdapter.java | 36 - .../support/ExchangeHandlerDispatcher.java | 121 --- .../support/header/HeaderExchangeChannel.java | 239 ------ .../support/header/HeaderExchangeHandler.java | 251 ------ .../support/ExchangeHandlerAdapter.java | 2 +- .../support/header/HeaderExchangeHandler.java | 3 +- .../dubbo/remoting/PerformanceServerTest.java | 165 ---- .../handler/HeaderExchangeHandlerTest.java | 223 ------ .../support/header/HeartbeatHandlerTest.java | 146 ---- .../com/alibaba/dubbo/rpc/AsyncContext.java | 36 - .../alibaba/dubbo/rpc/AsyncContextImpl.java | 85 -- .../com/alibaba/dubbo/rpc/AsyncRpcResult.java | 116 --- .../java/com/alibaba/dubbo/rpc/Result.java | 111 --- .../com/alibaba/dubbo/rpc/RpcContext.java | 730 ------------------ .../java/com/alibaba/dubbo/rpc/RpcResult.java | 93 --- .../rpc/filter/ConsumerContextFilter.java | 56 -- .../dubbo/rpc/filter/ContextFilter.java | 82 -- .../dubbo/rpc/filter/ExceptionFilter.java | 136 ---- .../dubbo/rpc/proxy/AbstractProxyFactory.java | 70 -- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 105 --- .../rpc/proxy/InvokerInvocationHandler.java | 74 -- .../alibaba/dubbo/rpc/support/RpcUtils.java | 209 ----- .../apache}/dubbo/rpc/AbstractResult.java | 2 +- .../org/apache/dubbo/rpc/AsyncContext.java | 7 + .../apache/dubbo/rpc/AsyncContextImpl.java | 16 +- .../org/apache/dubbo/rpc/AsyncResult.java | 60 -- .../org/apache/dubbo/rpc/AsyncRpcResult.java | 95 ++- .../apache}/dubbo/rpc/PostProcessFilter.java | 2 +- .../java/org/apache/dubbo/rpc/Result.java | 18 +- .../java/org/apache/dubbo/rpc/RpcContext.java | 43 +- .../java/org/apache/dubbo/rpc/RpcResult.java | 58 +- .../rpc/filter/ConsumerContextFilter.java | 3 +- .../dubbo/rpc/filter/ContextFilter.java | 3 +- .../dubbo/rpc/filter/ExceptionFilter.java | 117 +-- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 15 +- .../rpc/proxy/InvokerInvocationHandler.java | 8 +- .../apache/dubbo/rpc/support/RpcUtils.java | 40 +- .../dubbo/rpc/protocol/dubbo/DubboCodec.java | 220 ------ .../rpc/protocol/dubbo/DubboInvoker.java | 158 ---- .../rpc/protocol/dubbo/DubboProtocol.java | 492 ------------ .../rpc/protocol/dubbo/FutureAdapter.java | 107 --- .../dubbo/rpc/protocol/dubbo/DubboCodec.java | 3 +- .../rpc/protocol/dubbo/DubboInvoker.java | 8 +- .../rpc/protocol/dubbo/DubboProtocol.java | 20 +- .../rpc/protocol/thrift/ThriftProtocol.java | 220 ------ .../rpc/protocol/thrift/ThriftProtocol.java | 1 - .../test/provider/DefaultDemoService.java | 7 + 64 files changed, 361 insertions(+), 6602 deletions(-) delete mode 100644 dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java delete mode 100644 dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java delete mode 100644 dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java delete mode 100644 dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java delete mode 100644 dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java rename dubbo-demo/dubbo-demo-api/src/main/java/{com/alibaba => org/apache}/dubbo/demo/DemoServiceAsync.java (92%) delete mode 100644 dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java delete mode 100644 dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java delete mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java delete mode 100644 dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java delete mode 100644 dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java rename dubbo-rpc/dubbo-rpc-api/src/main/java/{com/alibaba => org/apache}/dubbo/rpc/AbstractResult.java (98%) delete mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncResult.java rename dubbo-rpc/dubbo-rpc-api/src/main/java/{com/alibaba => org/apache}/dubbo/rpc/PostProcessFilter.java (97%) delete mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java delete mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java delete mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java delete mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java delete mode 100644 dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java diff --git a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java deleted file mode 100644 index 9739f553aeb..00000000000 --- a/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/support/ClusterUtils.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.cluster.support; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; - -import java.util.HashMap; -import java.util.Map; - -/** - * ClusterUtils - * - */ -public class ClusterUtils { - - private ClusterUtils() { - } - - public static URL mergeUrl(URL remoteUrl, Map localMap) { - Map map = new HashMap(); - Map remoteMap = remoteUrl.getParameters(); - - - if (remoteMap != null && remoteMap.size() > 0) { - map.putAll(remoteMap); - - // Remove configurations from provider, some items should be affected by provider. - map.remove(Constants.THREAD_NAME_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREAD_NAME_KEY); - - map.remove(Constants.THREADPOOL_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADPOOL_KEY); - - map.remove(Constants.CORE_THREADS_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.CORE_THREADS_KEY); - - map.remove(Constants.THREADS_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADS_KEY); - - map.remove(Constants.QUEUES_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.QUEUES_KEY); - - map.remove(Constants.ALIVE_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ALIVE_KEY); - - map.remove(Constants.TRANSPORTER_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY); - - map.remove(Constants.ASYNC_KEY); - map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ASYNC_KEY); - } - - if (localMap != null && localMap.size() > 0) { - map.putAll(localMap); - } - if (remoteMap != null && remoteMap.size() > 0) { - // Use version passed from provider side - String dubbo = remoteMap.get(Constants.DUBBO_VERSION_KEY); - if (dubbo != null && dubbo.length() > 0) { - map.put(Constants.DUBBO_VERSION_KEY, dubbo); - } - String version = remoteMap.get(Constants.VERSION_KEY); - if (version != null && version.length() > 0) { - map.put(Constants.VERSION_KEY, version); - } - String group = remoteMap.get(Constants.GROUP_KEY); - if (group != null && group.length() > 0) { - map.put(Constants.GROUP_KEY, group); - } - String methods = remoteMap.get(Constants.METHODS_KEY); - if (methods != null && methods.length() > 0) { - map.put(Constants.METHODS_KEY, methods); - } - // Reserve timestamp of provider url. - String remoteTimestamp = remoteMap.get(Constants.TIMESTAMP_KEY); - if (remoteTimestamp != null && remoteTimestamp.length() > 0) { - map.put(Constants.REMOTE_TIMESTAMP_KEY, remoteMap.get(Constants.TIMESTAMP_KEY)); - } - // Combine filters and listeners on Provider and Consumer - String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY); - String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY); - if (remoteFilter != null && remoteFilter.length() > 0 - && localFilter != null && localFilter.length() > 0) { - localMap.put(Constants.REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter); - } - String remoteListener = remoteMap.get(Constants.INVOKER_LISTENER_KEY); - String localListener = localMap.get(Constants.INVOKER_LISTENER_KEY); - if (remoteListener != null && remoteListener.length() > 0 - && localListener != null && localListener.length() > 0) { - localMap.put(Constants.INVOKER_LISTENER_KEY, remoteListener + "," + localListener); - } - } - - return remoteUrl.clearParameters().addParameters(map); - } - -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java deleted file mode 100644 index 5d650a76078..00000000000 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.dubbo.common; - -import java.util.concurrent.ExecutorService; -import java.util.regex.Pattern; - -/** - * Constants - */ -public class Constants { - - public static final String PROVIDER = "provider"; - - public static final String CONSUMER = "consumer"; - - public static final String REGISTER = "register"; - - public static final String UNREGISTER = "unregister"; - - public static final String SUBSCRIBE = "subscribe"; - - public static final String UNSUBSCRIBE = "unsubscribe"; - - public static final String CATEGORY_KEY = "category"; - - public static final String PROVIDERS_CATEGORY = "providers"; - - public static final String CONSUMERS_CATEGORY = "consumers"; - - public static final String ROUTERS_CATEGORY = "routers"; - - public static final String CONFIGURATORS_CATEGORY = "configurators"; - - public static final String DEFAULT_CATEGORY = PROVIDERS_CATEGORY; - - public static final String ENABLED_KEY = "enabled"; - - public static final String DISABLED_KEY = "disabled"; - - public static final String VALIDATION_KEY = "validation"; - - public static final String CACHE_KEY = "cache"; - - public static final String DYNAMIC_KEY = "dynamic"; - - public static final String DUBBO_PROPERTIES_KEY = "dubbo.properties.file"; - - public static final String DEFAULT_DUBBO_PROPERTIES = "dubbo.properties"; - - public static final String SENT_KEY = "sent"; - - public static final boolean DEFAULT_SENT = false; - - public static final String REGISTRY_PROTOCOL = "registry"; - - public static final String $INVOKE = "$invoke"; - - public static final String $ECHO = "$echo"; - - public static final int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32); - - public static final String DEFAULT_PROXY = "javassist"; - - public static final int DEFAULT_PAYLOAD = 8 * 1024 * 1024; // 8M - - public static final String DEFAULT_CLUSTER = "failover"; - - public static final String DEFAULT_DIRECTORY = "dubbo"; - - public static final String DEFAULT_LOADBALANCE = "random"; - - public static final String DEFAULT_PROTOCOL = "dubbo"; - - public static final String DEFAULT_EXCHANGER = "header"; - - public static final String DEFAULT_TRANSPORTER = "netty"; - - public static final String DEFAULT_REMOTING_SERVER = "netty"; - - public static final String DEFAULT_REMOTING_CLIENT = "netty"; - - public static final String DEFAULT_REMOTING_CODEC = "dubbo"; - - public static final String DEFAULT_REMOTING_SERIALIZATION = "hessian2"; - - public static final String DEFAULT_HTTP_SERVER = "servlet"; - - public static final String DEFAULT_HTTP_CLIENT = "jdk"; - - public static final String DEFAULT_HTTP_SERIALIZATION = "json"; - - public static final String DEFAULT_CHARSET = "UTF-8"; - - public static final int DEFAULT_WEIGHT = 100; - - public static final int DEFAULT_FORKS = 2; - - public static final String DEFAULT_THREAD_NAME = "Dubbo"; - - public static final int DEFAULT_CORE_THREADS = 0; - - public static final int DEFAULT_THREADS = 200; - - public static final boolean DEFAULT_KEEP_ALIVE = true; - - public static final int DEFAULT_QUEUES = 0; - - public static final int DEFAULT_ALIVE = 60 * 1000; - - public static final int DEFAULT_CONNECTIONS = 0; - - public static final int DEFAULT_ACCEPTS = 0; - - public static final int DEFAULT_IDLE_TIMEOUT = 600 * 1000; - - public static final int DEFAULT_HEARTBEAT = 60 * 1000; - - public static final int DEFAULT_TIMEOUT = 1000; - - public static final int DEFAULT_CONNECT_TIMEOUT = 3000; - -// public static final int DEFAULT_REGISTRY_CONNECT_TIMEOUT = 5000; - - public static final int DEFAULT_RETRIES = 2; - - // default buffer size is 8k. - public static final int DEFAULT_BUFFER_SIZE = 8 * 1024; - - public static final int MAX_BUFFER_SIZE = 16 * 1024; - - public static final int MIN_BUFFER_SIZE = 1 * 1024; - - public static final String REMOVE_VALUE_PREFIX = "-"; - - public static final String HIDE_KEY_PREFIX = "."; - - public static final String DEFAULT_KEY_PREFIX = "default."; - - public static final String DEFAULT_KEY = "default"; - - public static final String LOADBALANCE_KEY = "loadbalance"; - - // key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME - public static final String ROUTER_KEY = "router"; - - public static final String CLUSTER_KEY = "cluster"; - - public static final String REGISTRY_KEY = "registry"; - - public static final String MONITOR_KEY = "monitor"; - - public static final String SIDE_KEY = "side"; - - public static final String PROVIDER_SIDE = "provider"; - - public static final String CONSUMER_SIDE = "consumer"; - - public static final String DEFAULT_REGISTRY = "dubbo"; - - public static final String BACKUP_KEY = "backup"; - - public static final String DIRECTORY_KEY = "directory"; - - public static final String DEPRECATED_KEY = "deprecated"; - - public static final String ANYHOST_KEY = "anyhost"; - - public static final String ANYHOST_VALUE = "0.0.0.0"; - - public static final String LOCALHOST_KEY = "localhost"; - - public static final String LOCALHOST_VALUE = "127.0.0.1"; - - public static final String APPLICATION_KEY = "application"; - - public static final String LOCAL_KEY = "local"; - - public static final String STUB_KEY = "stub"; - - public static final String MOCK_KEY = "mock"; - - public static final String PROTOCOL_KEY = "protocol"; - - public static final String PROXY_KEY = "proxy"; - - public static final String WEIGHT_KEY = "weight"; - - public static final String FORKS_KEY = "forks"; - - public static final String DEFAULT_THREADPOOL = "limited"; - - public static final String DEFAULT_CLIENT_THREADPOOL = "cached"; - - public static final String THREADPOOL_KEY = "threadpool"; - - public static final String THREAD_NAME_KEY = "threadname"; - - public static final String IO_THREADS_KEY = "iothreads"; - - public static final String CORE_THREADS_KEY = "corethreads"; - - public static final String THREADS_KEY = "threads"; - - public static final String QUEUES_KEY = "queues"; - - public static final String ALIVE_KEY = "alive"; - - public static final String EXECUTES_KEY = "executes"; - - public static final String BUFFER_KEY = "buffer"; - - public static final String PAYLOAD_KEY = "payload"; - - public static final String REFERENCE_FILTER_KEY = "reference.filter"; - - public static final String INVOKER_LISTENER_KEY = "invoker.listener"; - - public static final String SERVICE_FILTER_KEY = "service.filter"; - - public static final String EXPORTER_LISTENER_KEY = "exporter.listener"; - - public static final String ACCESS_LOG_KEY = "accesslog"; - - public static final String ACTIVES_KEY = "actives"; - - public static final String CONNECTIONS_KEY = "connections"; - - public static final String ACCEPTS_KEY = "accepts"; - - public static final String IDLE_TIMEOUT_KEY = "idle.timeout"; - - public static final String HEARTBEAT_KEY = "heartbeat"; - - public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout"; - - public static final String CONNECT_TIMEOUT_KEY = "connect.timeout"; - - public static final String TIMEOUT_KEY = "timeout"; - - public static final String RETRIES_KEY = "retries"; - - public static final String PROMPT_KEY = "prompt"; - - public static final String DEFAULT_PROMPT = "dubbo>"; - - public static final String CODEC_KEY = "codec"; - - public static final String SERIALIZATION_KEY = "serialization"; - - public static final String EXTENSION_KEY = "extension"; - - public static final String KEEP_ALIVE_KEY = "keepalive"; - - public static final String OPTIMIZER_KEY = "optimizer"; - - public static final String EXCHANGER_KEY = "exchanger"; - - public static final String TRANSPORTER_KEY = "transporter"; - - public static final String SERVER_KEY = "server"; - - public static final String CLIENT_KEY = "client"; - - public static final String ID_KEY = "id"; - - public static final String ASYNC_KEY = "async"; - - public static final String FUTURE_GENERATED_KEY = "future_generated"; - public static final String FUTURE_RETURNTYPE_KEY = "future_returntype"; - - public static final String ASYNC_SUFFIX = "Async"; - - public static final String RETURN_KEY = "return"; - - public static final String TOKEN_KEY = "token"; - - public static final String METHOD_KEY = "method"; - - public static final String METHODS_KEY = "methods"; - - public static final String CHARSET_KEY = "charset"; - - public static final String RECONNECT_KEY = "reconnect"; - - public static final String SEND_RECONNECT_KEY = "send.reconnect"; - - public static final int DEFAULT_RECONNECT_PERIOD = 2000; - - public static final String SHUTDOWN_TIMEOUT_KEY = "shutdown.timeout"; - - public static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 60 * 15; - - public static final String PID_KEY = "pid"; - - public static final String TIMESTAMP_KEY = "timestamp"; - - public static final String REMOTE_TIMESTAMP_KEY = "remote.timestamp"; - - public static final String WARMUP_KEY = "warmup"; - - public static final int DEFAULT_WARMUP = 10 * 60 * 1000; - - public static final String CHECK_KEY = "check"; - - public static final String REGISTER_KEY = "register"; - - public static final String SUBSCRIBE_KEY = "subscribe"; - - public static final String GROUP_KEY = "group"; - - public static final String PATH_KEY = "path"; - - public static final String INTERFACE_KEY = "interface"; - - public static final String INTERFACES = "interfaces"; - - public static final String GENERIC_KEY = "generic"; - - public static final String FILE_KEY = "file"; - - public static final String DUMP_DIRECTORY = "dump.directory"; - - public static final String WAIT_KEY = "wait"; - - public static final String CLASSIFIER_KEY = "classifier"; - - public static final String VERSION_KEY = "version"; - - public static final String REVISION_KEY = "revision"; - - public static final String DUBBO_VERSION_KEY = "dubbo"; - - public static final String HESSIAN_VERSION_KEY = "hessian.version"; - - public static final String DISPATCHER_KEY = "dispatcher"; - - public static final String CHANNEL_HANDLER_KEY = "channel.handler"; - - public static final String DEFAULT_CHANNEL_HANDLER = "default"; - - public static final String ANY_VALUE = "*"; - - public static final String COMMA_SEPARATOR = ","; - - public static final Pattern COMMA_SPLIT_PATTERN = Pattern - .compile("\\s*[,]+\\s*"); - - public final static String PATH_SEPARATOR = "/"; - - public static final String REGISTRY_SEPARATOR = "|"; - - public static final Pattern REGISTRY_SPLIT_PATTERN = Pattern - .compile("\\s*[|;]+\\s*"); - - public static final String SEMICOLON_SEPARATOR = ";"; - - public static final Pattern SEMICOLON_SPLIT_PATTERN = Pattern - .compile("\\s*[;]+\\s*"); - - public static final String CONNECT_QUEUE_CAPACITY = "connect.queue.capacity"; - - public static final String CONNECT_QUEUE_WARNING_SIZE = "connect.queue.warning.size"; - - public static final int DEFAULT_CONNECT_QUEUE_WARNING_SIZE = 1000; - - public static final String CHANNEL_ATTRIBUTE_READONLY_KEY = "channel.readonly"; - - public static final String CHANNEL_READONLYEVENT_SENT_KEY = "channel.readonly.sent"; - - public static final String CHANNEL_SEND_READONLYEVENT_KEY = "channel.readonly.send"; - - public static final String COUNT_PROTOCOL = "count"; - - public static final String TRACE_PROTOCOL = "trace"; - - public static final String EMPTY_PROTOCOL = "empty"; - - public static final String ADMIN_PROTOCOL = "admin"; - - public static final String PROVIDER_PROTOCOL = "provider"; - - public static final String CONSUMER_PROTOCOL = "consumer"; - - public static final String ROUTE_PROTOCOL = "route"; - - public static final String SCRIPT_PROTOCOL = "script"; - - public static final String CONDITION_PROTOCOL = "condition"; - - public static final String MOCK_PROTOCOL = "mock"; - - public static final String RETURN_PREFIX = "return "; - - public static final String THROW_PREFIX = "throw"; - - public static final String FAIL_PREFIX = "fail:"; - - public static final String FORCE_PREFIX = "force:"; - - public static final String FORCE_KEY = "force"; - - public static final String MERGER_KEY = "merger"; - - /** - * To decide whether to exclude unavailable invoker from the cluster - */ - public static final String CLUSTER_AVAILABLE_CHECK_KEY = "cluster.availablecheck"; - - /** - * The default value of cluster.availablecheck - * - * @see #CLUSTER_AVAILABLE_CHECK_KEY - */ - public static final boolean DEFAULT_CLUSTER_AVAILABLE_CHECK = true; - - /** - * To decide whether to enable sticky strategy for cluster - */ - public static final String CLUSTER_STICKY_KEY = "sticky"; - - /** - * The default value of sticky - * - * @see #CLUSTER_STICKY_KEY - */ - public static final boolean DEFAULT_CLUSTER_STICKY = false; - - /** - * To decide whether to make connection when the client is created - */ - public static final String LAZY_CONNECT_KEY = "lazy"; - - /** - * The initial state for lazy connection - */ - public static final String LAZY_CONNECT_INITIAL_STATE_KEY = "connect.lazy.initial.state"; - - /** - * The default value of lazy connection's initial state: true - * - * @see #LAZY_CONNECT_INITIAL_STATE_KEY - */ - public static final boolean DEFAULT_LAZY_CONNECT_INITIAL_STATE = true; - - /** - * To decide whether register center saves file synchronously, the default value is asynchronously - */ - public static final String REGISTRY_FILESAVE_SYNC_KEY = "save.file"; - - /** - * Period of registry center's retry interval - */ - public static final String REGISTRY_RETRY_PERIOD_KEY = "retry.period"; - - /** - * Default value for the period of retry interval in milliseconds: 5000 - */ - public static final int DEFAULT_REGISTRY_RETRY_PERIOD = 5 * 1000; - - /** - * Reconnection period in milliseconds for register center - */ - public static final String REGISTRY_RECONNECT_PERIOD_KEY = "reconnect.period"; - - public static final int DEFAULT_REGISTRY_RECONNECT_PERIOD = 3 * 1000; - - public static final String SESSION_TIMEOUT_KEY = "session"; - - public static final int DEFAULT_SESSION_TIMEOUT = 60 * 1000; - - /** - * The key name for export URL in register center - */ - public static final String EXPORT_KEY = "export"; - - /** - * The key name for reference URL in register center - */ - public static final String REFER_KEY = "refer"; - - /** - * callback inst id - */ - public static final String CALLBACK_SERVICE_KEY = "callback.service.instid"; - - /** - * The limit of callback service instances for one interface on every client - */ - public static final String CALLBACK_INSTANCES_LIMIT_KEY = "callbacks"; - - /** - * The default limit number for callback service instances - * - * @see #CALLBACK_INSTANCES_LIMIT_KEY - */ - public static final int DEFAULT_CALLBACK_INSTANCES = 1; - - public static final String CALLBACK_SERVICE_PROXY_KEY = "callback.service.proxy"; - - public static final String IS_CALLBACK_SERVICE = "is_callback_service"; - - /** - * Invokers in channel's callback - */ - public static final String CHANNEL_CALLBACK_KEY = "channel.callback.invokers.key"; - - @Deprecated - public static final String SHUTDOWN_WAIT_SECONDS_KEY = "dubbo.service.shutdown.wait.seconds"; - - public static final String SHUTDOWN_WAIT_KEY = "dubbo.service.shutdown.wait"; - - public static final String IS_SERVER_KEY = "isserver"; - - /** - * Default timeout value in milliseconds for server shutdown - */ - public static final int DEFAULT_SERVER_SHUTDOWN_TIMEOUT = 10000; - - public static final String ON_CONNECT_KEY = "onconnect"; - - public static final String ON_DISCONNECT_KEY = "ondisconnect"; - - public static final String ON_INVOKE_METHOD_KEY = "oninvoke.method"; - - public static final String ON_RETURN_METHOD_KEY = "onreturn.method"; - - public static final String ON_THROW_METHOD_KEY = "onthrow.method"; - - public static final String ON_INVOKE_INSTANCE_KEY = "oninvoke.instance"; - - public static final String ON_RETURN_INSTANCE_KEY = "onreturn.instance"; - - public static final String ON_THROW_INSTANCE_KEY = "onthrow.instance"; - - public static final String OVERRIDE_PROTOCOL = "override"; - - public static final String PRIORITY_KEY = "priority"; - - public static final String RULE_KEY = "rule"; - - public static final String TYPE_KEY = "type"; - - public static final String RUNTIME_KEY = "runtime"; - - /** - * when ROUTER_KEY's value is set to ROUTER_TYPE_CLEAR, RegistryDirectory will clean all current routers - */ - public static final String ROUTER_TYPE_CLEAR = "clean"; - - public static final String DEFAULT_SCRIPT_TYPE_KEY = "javascript"; - - public static final String STUB_EVENT_KEY = "dubbo.stub.event"; - - public static final boolean DEFAULT_STUB_EVENT = false; - - public static final String STUB_EVENT_METHODS_KEY = "dubbo.stub.event.methods"; - - /** - * When this attribute appears in invocation's attachment, mock invoker will be used - */ - public static final String INVOCATION_NEED_MOCK = "invocation.need.mock"; - - public static final String LOCAL_PROTOCOL = "injvm"; - - public static final String AUTO_ATTACH_INVOCATIONID_KEY = "invocationid.autoattach"; - - public static final String SCOPE_KEY = "scope"; - - public static final String SCOPE_LOCAL = "local"; - - public static final String SCOPE_REMOTE = "remote"; - - public static final String SCOPE_NONE = "none"; - - public static final String RELIABLE_PROTOCOL = "napoli"; - - public static final String TPS_LIMIT_RATE_KEY = "tps"; - - public static final String TPS_LIMIT_INTERVAL_KEY = "tps.interval"; - - public static final long DEFAULT_TPS_LIMIT_INTERVAL = 60 * 1000; - - public static final String DECODE_IN_IO_THREAD_KEY = "decode.in.io"; - - public static final boolean DEFAULT_DECODE_IN_IO_THREAD = true; - - public static final String INPUT_KEY = "input"; - - public static final String OUTPUT_KEY = "output"; - - public static final String EXECUTOR_SERVICE_COMPONENT_KEY = ExecutorService.class.getName(); - - public static final String GENERIC_SERIALIZATION_NATIVE_JAVA = "nativejava"; - - public static final String GENERIC_SERIALIZATION_DEFAULT = "true"; - - public static final String GENERIC_SERIALIZATION_BEAN = "bean"; - - public static final String DUBBO_IP_TO_REGISTRY = "DUBBO_IP_TO_REGISTRY"; - - public static final String DUBBO_PORT_TO_REGISTRY = "DUBBO_PORT_TO_REGISTRY"; - - public static final String DUBBO_IP_TO_BIND = "DUBBO_IP_TO_BIND"; - - public static final String DUBBO_PORT_TO_BIND = "DUBBO_PORT_TO_BIND"; - - public static final String BIND_IP_KEY = "bind.ip"; - - public static final String BIND_PORT_KEY = "bind.port"; - - public static final String REGISTER_IP_KEY = "register.ip"; - - public static final String QOS_ENABLE = "qos.enable"; - - public static final String QOS_PORT = "qos.port"; - - public static final String ACCEPT_FOREIGN_IP = "qos.accept.foreign.ip"; - - public static final String HESSIAN2_REQUEST_KEY = "hessian2.request"; - - public static final boolean DEFAULT_HESSIAN2_REQUEST = false; - - public static final String HESSIAN_OVERLOAD_METHOD_KEY = "hessian.overload.method"; - - public static final boolean DEFAULT_HESSIAN_OVERLOAD_METHOD = false; - - public static final String MULTICAST = "multicast"; - - /* - * private Constants(){ } - */ - -} diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java deleted file mode 100644 index fbdee563e59..00000000000 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/config/AsyncFor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.common.config; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * TODO This definition should better be placed in module 'dubbo-config-api', but only can be done when "rpc" dependencies are removed from "dubbo-config-api" - * If an interface is annotated with AsyncFor, it will be treated as an async counterpart for the sync one. - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) -public @interface AsyncFor { - - /** - * The original sync-style interface - * - * @return - */ - Class value(); - -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java index 0304af69eb9..a1c8fac34c6 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java @@ -19,7 +19,6 @@ import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; - /** * Constants */ @@ -281,7 +280,8 @@ public class Constants { public static final String ASYNC_KEY = "async"; - public static final String FUTURE_KEY = "async_future"; + public static final String FUTURE_GENERATED_KEY = "future_generated"; + public static final String FUTURE_RETURNTYPE_KEY = "future_returntype"; public static final String ASYNC_SUFFIX = "Async"; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AsyncFor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/AsyncFor.java index be5d66119e4..dee04fcbc00 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/AsyncFor.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/AsyncFor.java @@ -39,3 +39,4 @@ Class value(); } + diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java deleted file mode 100644 index 9f9bc76312f..00000000000 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.config; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.Version; -import com.alibaba.dubbo.common.bytecode.Wrapper; -import com.alibaba.dubbo.common.config.AsyncFor; -import com.alibaba.dubbo.common.extension.ExtensionLoader; -import com.alibaba.dubbo.common.utils.ConfigUtils; -import com.alibaba.dubbo.common.utils.NetUtils; -import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.config.annotation.Reference; -import com.alibaba.dubbo.config.model.ApplicationModel; -import com.alibaba.dubbo.config.model.ConsumerModel; -import com.alibaba.dubbo.config.support.Parameter; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Protocol; -import com.alibaba.dubbo.rpc.ProxyFactory; -import com.alibaba.dubbo.rpc.StaticContext; -import com.alibaba.dubbo.rpc.cluster.Cluster; -import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory; -import com.alibaba.dubbo.rpc.cluster.support.AvailableCluster; -import com.alibaba.dubbo.rpc.cluster.support.ClusterUtils; -import com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol; -import com.alibaba.dubbo.rpc.service.GenericService; -import com.alibaba.dubbo.rpc.support.ProtocolUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidLocalHost; - -/** - * ReferenceConfig - * - * @export - */ -public class ReferenceConfig extends AbstractReferenceConfig { - - private static final long serialVersionUID = -5864351140409987595L; - - private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - - private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension(); - - private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); - private final List urls = new ArrayList(); - // interface name - private String interfaceName; - private Class interfaceClass; - private Class asyncInterfaceClass; - // client type - private String client; - // url for peer-to-peer invocation - private String url; - // method configs - private List methods; - // default config - private ConsumerConfig consumer; - private String protocol; - // interface proxy reference - private transient volatile T ref; - private transient volatile Invoker invoker; - private transient volatile boolean initialized; - private transient volatile boolean destroyed; - @SuppressWarnings("unused") - private final Object finalizerGuardian = new Object() { - @Override - protected void finalize() throws Throwable { - super.finalize(); - - if (!ReferenceConfig.this.destroyed) { - logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE"); - - /* don't destroy for now - try { - ReferenceConfig.this.destroy(); - } catch (Throwable t) { - logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t); - } - */ - } - } - }; - - public ReferenceConfig() { - } - - public ReferenceConfig(Reference reference) { - appendAnnotation(Reference.class, reference); - } - - private static void checkAndConvertImplicitConfig(MethodConfig method, Map map, Map attributes) { - //check config conflict - if (Boolean.FALSE.equals(method.isReturn()) && (method.getOnreturn() != null || method.getOnthrow() != null)) { - throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been setted."); - } - //convert onreturn methodName to Method - String onReturnMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_RETURN_METHOD_KEY); - Object onReturnMethod = attributes.get(onReturnMethodKey); - if (onReturnMethod instanceof String) { - attributes.put(onReturnMethodKey, getMethodByName(method.getOnreturn().getClass(), onReturnMethod.toString())); - } - //convert onthrow methodName to Method - String onThrowMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_THROW_METHOD_KEY); - Object onThrowMethod = attributes.get(onThrowMethodKey); - if (onThrowMethod instanceof String) { - attributes.put(onThrowMethodKey, getMethodByName(method.getOnthrow().getClass(), onThrowMethod.toString())); - } - //convert oninvoke methodName to Method - String onInvokeMethodKey = StaticContext.getKey(map, method.getName(), Constants.ON_INVOKE_METHOD_KEY); - Object onInvokeMethod = attributes.get(onInvokeMethodKey); - if (onInvokeMethod instanceof String) { - attributes.put(onInvokeMethodKey, getMethodByName(method.getOninvoke().getClass(), onInvokeMethod.toString())); - } - } - - private static Method getMethodByName(Class clazz, String methodName) { - try { - return ReflectUtils.findMethodByMethodName(clazz, methodName); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - public URL toUrl() { - return urls.isEmpty() ? null : urls.iterator().next(); - } - - public List toUrls() { - return urls; - } - - public synchronized T get() { - if (destroyed) { - throw new IllegalStateException("Already destroyed!"); - } - if (ref == null) { - init(); - } - return ref; - } - - public synchronized void destroy() { - if (ref == null) { - return; - } - if (destroyed) { - return; - } - destroyed = true; - try { - invoker.destroy(); - } catch (Throwable t) { - logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ").", t); - } - invoker = null; - ref = null; - } - - private void init() { - if (initialized) { - return; - } - initialized = true; - if (interfaceName == null || interfaceName.length() == 0) { - throw new IllegalStateException(" interface not allow null!"); - } - // get consumer's global configuration - checkDefault(); - appendProperties(this); - if (getGeneric() == null && getConsumer() != null) { - setGeneric(getConsumer().getGeneric()); - } - if (ProtocolUtils.isGeneric(getGeneric())) { - interfaceClass = GenericService.class; - } else { - try { - interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - checkInterfaceAndMethods(interfaceClass, methods); - } - String resolve = System.getProperty(interfaceName); - String resolveFile = null; - if (resolve == null || resolve.length() == 0) { - resolveFile = System.getProperty("dubbo.resolve.file"); - if (resolveFile == null || resolveFile.length() == 0) { - File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties"); - if (userResolveFile.exists()) { - resolveFile = userResolveFile.getAbsolutePath(); - } - } - if (resolveFile != null && resolveFile.length() > 0) { - Properties properties = new Properties(); - FileInputStream fis = null; - try { - fis = new FileInputStream(new File(resolveFile)); - properties.load(fis); - } catch (IOException e) { - throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e); - } finally { - try { - if (null != fis) fis.close(); - } catch (IOException e) { - logger.warn(e.getMessage(), e); - } - } - resolve = properties.getProperty(interfaceName); - } - } - if (resolve != null && resolve.length() > 0) { - url = resolve; - if (logger.isWarnEnabled()) { - if (resolveFile != null) { - logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service."); - } else { - logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service."); - } - } - } - if (consumer != null) { - if (application == null) { - application = consumer.getApplication(); - } - if (module == null) { - module = consumer.getModule(); - } - if (registries == null) { - registries = consumer.getRegistries(); - } - if (monitor == null) { - monitor = consumer.getMonitor(); - } - } - if (module != null) { - if (registries == null) { - registries = module.getRegistries(); - } - if (monitor == null) { - monitor = module.getMonitor(); - } - } - if (application != null) { - if (registries == null) { - registries = application.getRegistries(); - } - if (monitor == null) { - monitor = application.getMonitor(); - } - } - checkApplication(); - checkStubAndMock(interfaceClass); - Map map = new HashMap(); - resolveAsyncInterface(interfaceClass, map); - Map attributes = new HashMap(); - map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE); - map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()); - map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); - if (ConfigUtils.getPid() > 0) { - map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); - } - if (!isGeneric()) { - String revision = Version.getVersion(interfaceClass, version); - if (revision != null && revision.length() > 0) { - map.put("revision", revision); - } - - String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); - if (methods.length == 0) { - logger.warn("NO method found in service interface " + interfaceClass.getName()); - map.put("methods", Constants.ANY_VALUE); - } else { - map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ",")); - } - } - map.put(Constants.INTERFACE_KEY, interfaceName); - appendParameters(map, application); - appendParameters(map, module); - appendParameters(map, consumer, Constants.DEFAULT_KEY); - appendParameters(map, this); - String prefix = StringUtils.getServiceKey(map); - if (methods != null && !methods.isEmpty()) { - for (MethodConfig method : methods) { - appendParameters(map, method, method.getName()); - String retryKey = method.getName() + ".retry"; - if (map.containsKey(retryKey)) { - String retryValue = map.remove(retryKey); - if ("false".equals(retryValue)) { - map.put(method.getName() + ".retries", "0"); - } - } - appendAttributes(attributes, method, prefix + "." + method.getName()); - checkAndConvertImplicitConfig(method, map, attributes); - } - } - - String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); - if (hostToRegistry == null || hostToRegistry.length() == 0) { - hostToRegistry = NetUtils.getLocalHost(); - } else if (isInvalidLocalHost(hostToRegistry)) { - throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); - } - map.put(Constants.REGISTER_IP_KEY, hostToRegistry); - - //attributes are stored by system context. - StaticContext.getSystemContext().putAll(attributes); - ref = createProxy(map); - ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods()); - ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel); - } - - @SuppressWarnings({"unchecked", "rawtypes", "deprecation"}) - private T createProxy(Map map) { - URL tmpUrl = new URL("temp", "localhost", 0, map); - final boolean isJvmRefer; - if (isInjvm() == null) { - if (url != null && url.length() > 0) { // if a url is specified, don't do local reference - isJvmRefer = false; - } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { - // by default, reference local service if there is - isJvmRefer = true; - } else { - isJvmRefer = false; - } - } else { - isJvmRefer = isInjvm().booleanValue(); - } - - if (isJvmRefer) { - URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map); - invoker = refprotocol.refer(interfaceClass, url); - if (logger.isInfoEnabled()) { - logger.info("Using injvm service " + interfaceClass.getName()); - } - } else { - if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address. - String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url); - if (us != null && us.length > 0) { - for (String u : us) { - URL url = URL.valueOf(u); - if (url.getPath() == null || url.getPath().length() == 0) { - url = url.setPath(interfaceName); - } - if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { - urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); - } else { - urls.add(ClusterUtils.mergeUrl(url, map)); - } - } - } - } else { // assemble URL from register center's configuration - List us = loadRegistries(false); - if (us != null && !us.isEmpty()) { - for (URL u : us) { - URL monitorUrl = loadMonitor(u); - if (monitorUrl != null) { - map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString())); - } - urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); - } - } - if (urls.isEmpty()) { - throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config to your spring config."); - } - } - - if (urls.size() == 1) { - invoker = refprotocol.refer(interfaceClass, urls.get(0)); - } else { - List> invokers = new ArrayList>(); - URL registryURL = null; - for (URL url : urls) { - invokers.add(refprotocol.refer(interfaceClass, url)); - if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { - registryURL = url; // use last registry url - } - } - if (registryURL != null) { // registry url is available - // use AvailableCluster only when register's cluster is available - URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); - invoker = cluster.join(new StaticDirectory(u, invokers)); - } else { // not a registry url - invoker = cluster.join(new StaticDirectory(invokers)); - } - } - } - - Boolean c = check; - if (c == null && consumer != null) { - c = consumer.isCheck(); - } - if (c == null) { - c = true; // default true - } - if (c && !invoker.isAvailable()) { - throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); - } - if (logger.isInfoEnabled()) { - logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); - } - // create service proxy - return (T) proxyFactory.getProxy(invoker); - } - - private void checkDefault() { - if (consumer == null) { - consumer = new ConsumerConfig(); - } - appendProperties(consumer); - } - - private void resolveAsyncInterface(Class interfaceClass, Map map) { - AsyncFor annotation = interfaceClass.getAnnotation(AsyncFor.class); - if (annotation == null) return; - Class target = annotation.value(); - if (!target.isAssignableFrom(interfaceClass)) return; - this.asyncInterfaceClass = interfaceClass; - this.interfaceClass = target; - setInterface(this.interfaceClass.getName()); - map.put(Constants.INTERFACES, interfaceClass.getName()); - } - - - public Class getInterfaceClass() { - if (interfaceClass != null) { - return interfaceClass; - } - if (isGeneric() - || (getConsumer() != null && getConsumer().isGeneric())) { - return GenericService.class; - } - try { - if (interfaceName != null && interfaceName.length() > 0) { - this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } - } catch (ClassNotFoundException t) { - throw new IllegalStateException(t.getMessage(), t); - } - return interfaceClass; - } - - /** - * @param interfaceClass - * @see #setInterface(Class) - * @deprecated - */ - @Deprecated - public void setInterfaceClass(Class interfaceClass) { - setInterface(interfaceClass); - } - - public String getInterface() { - return interfaceName; - } - - public void setInterface(Class interfaceClass) { - if (interfaceClass != null && !interfaceClass.isInterface()) { - throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); - } - this.interfaceClass = interfaceClass; - setInterface(interfaceClass == null ? null : interfaceClass.getName()); - } - - public void setInterface(String interfaceName) { - this.interfaceName = interfaceName; - if (id == null || id.length() == 0) { - id = interfaceName; - } - } - - public String getClient() { - return client; - } - - public void setClient(String client) { - checkName("client", client); - this.client = client; - } - - @Parameter(excluded = true) - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public List getMethods() { - return methods; - } - - @SuppressWarnings("unchecked") - public void setMethods(List methods) { - this.methods = (List) methods; - } - - public ConsumerConfig getConsumer() { - return consumer; - } - - public void setConsumer(ConsumerConfig consumer) { - this.consumer = consumer; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - // just for test - Invoker getInvoker() { - return invoker; - } - - @Parameter(excluded = true) - public String getUniqueServiceName() { - StringBuilder buf = new StringBuilder(); - if (group != null && group.length() > 0) { - buf.append(group).append("/"); - } - buf.append(interfaceName); - if (version != null && version.length() > 0) { - buf.append(":").append(version); - } - return buf.toString(); - } - -} diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java deleted file mode 100644 index a00d8e57fdb..00000000000 --- a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoService.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.demo; - -import java.util.concurrent.CompletableFuture; - -public interface DemoService { - - String sayHello(String name); - - CompletableFuture originalFuture(String name); -} \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java index 1172c9be0fc..656413c83b0 100644 --- a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java +++ b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java @@ -16,8 +16,11 @@ */ package org.apache.dubbo.demo; +import java.util.concurrent.CompletableFuture; + public interface DemoService { String sayHello(String name); + CompletableFuture originalFuture(String name); } \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java similarity index 92% rename from dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java rename to dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java index 7325a6086f8..5027e7e175d 100644 --- a/dubbo-demo/dubbo-demo-api/src/main/java/com/alibaba/dubbo/demo/DemoServiceAsync.java +++ b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.demo; +package org.apache.dubbo.demo; -import com.alibaba.dubbo.common.config.AsyncFor; +import org.apache.dubbo.common.config.AsyncFor; import java.util.concurrent.CompletableFuture; diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java deleted file mode 100644 index 0f5c32582ee..00000000000 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/com/alibaba/dubbo/demo/consumer/Consumer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.demo.consumer; - -import com.alibaba.dubbo.demo.DemoService; -import com.alibaba.dubbo.demo.DemoServiceAsync; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.concurrent.CompletableFuture; - -public class Consumer { - - public static void main(String[] args) throws InterruptedException { - //Prevent to get IPV6 address,this way only work in debug mode - //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not - System.setProperty("java.net.preferIPv4Stack", "true"); - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); - context.start(); - DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy - DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoServiceAsync"); - - while (true) { - try { - try { - CompletableFuture future = demoService.originalFuture("world"); // call remote method - System.out.println(future.get()); // get result - } catch (Exception e) { - e.printStackTrace(); - } - -// System.out.println(demoService.sayHello("world")); - try { - CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); - System.out.println(generatedFuture.get()); - } catch (Exception e) { - e.printStackTrace(); - } - Thread.sleep(1000); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - } -} diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java index 384ff2db7fe..05cc9702db2 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java @@ -17,31 +17,42 @@ package org.apache.dubbo.demo.consumer; import org.apache.dubbo.demo.DemoService; - +import org.apache.dubbo.demo.DemoServiceAsync; import org.springframework.context.support.ClassPathXmlApplicationContext; +import java.util.concurrent.CompletableFuture; + public class Consumer { - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { //Prevent to get IPV6 address,this way only work in debug mode //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy + DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoServiceAsync"); while (true) { try { + try { + CompletableFuture future = demoService.originalFuture("world"); // call remote method + System.out.println(future.get()); // get result + } catch (Exception e) { + e.printStackTrace(); + } + +// System.out.println(demoService.sayHello("world")); + try { + CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); + System.out.println(generatedFuture.get()); + } catch (Exception e) { + e.printStackTrace(); + } Thread.sleep(1000); - String hello = demoService.sayHello("world"); // call remote method - System.out.println(hello); // get result - } catch (Throwable throwable) { throwable.printStackTrace(); } - - } - } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index 6ff76641084..a6f0c06283a 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -32,6 +32,6 @@ local regular interface --> - + \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java deleted file mode 100644 index b9d01001751..00000000000 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/com/alibaba/dubbo/demo/provider/DemoServiceImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.demo.provider; - -import com.alibaba.dubbo.demo.DemoService; -import com.alibaba.dubbo.rpc.AsyncContext; -import com.alibaba.dubbo.rpc.RpcContext; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.concurrent.CompletableFuture; - -public class DemoServiceImpl implements DemoService { - - @Override - public String sayHello(String name) { - System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - startAsync(name); - throw new RuntimeException("bbb"); -// return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); - } - - @Override - public CompletableFuture originalFuture(String name) { - return CompletableFuture.supplyAsync(() ->{ - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - throw new RuntimeException("aaa"); -// return "test Async"; - }); - } - - private void startAsync(String name) { - AsyncContext asyncContext = RpcContext.startAsync(); - new Thread(() -> { - System.out.println(" -- Async start."); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - asyncContext.write("Hello " + name + ", response from async provider."); - System.out.println(" -- Async end."); - }).start(); - } - -} diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java index 004f48d98bc..007f399a1a0 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java @@ -17,17 +17,50 @@ package org.apache.dubbo.demo.provider; import org.apache.dubbo.demo.DemoService; +import org.apache.dubbo.rpc.AsyncContext; import org.apache.dubbo.rpc.RpcContext; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.CompletableFuture; + public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + startAsync(name); +// throw new RuntimeException("bbb"); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } + @Override + public CompletableFuture originalFuture(String name) { + return CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } +// throw new RuntimeException("aaa"); + return "test Async"; + }); + } + + private void startAsync(String name) { + AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + System.out.println(" -- Async start."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from async provider."); + System.out.println(" -- Async end."); + }).start(); + } + } + diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index b696a07a39e..d5b105dcebf 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -31,9 +31,9 @@ - + - + \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java deleted file mode 100644 index e077eed20c4..00000000000 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.registry.integration; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.extension.ExtensionLoader; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.ConfigUtils; -import com.alibaba.dubbo.common.utils.NamedThreadFactory; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.common.utils.UrlUtils; -import com.alibaba.dubbo.registry.NotifyListener; -import com.alibaba.dubbo.registry.Registry; -import com.alibaba.dubbo.registry.RegistryFactory; -import com.alibaba.dubbo.registry.RegistryService; -import com.alibaba.dubbo.registry.support.ProviderConsumerRegTable; -import com.alibaba.dubbo.rpc.Exporter; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Protocol; -import com.alibaba.dubbo.rpc.ProxyFactory; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.cluster.Cluster; -import com.alibaba.dubbo.rpc.cluster.Configurator; -import com.alibaba.dubbo.rpc.protocol.InvokerWrapper; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static com.alibaba.dubbo.common.Constants.ACCEPT_FOREIGN_IP; -import static com.alibaba.dubbo.common.Constants.INTERFACES; -import static com.alibaba.dubbo.common.Constants.QOS_ENABLE; -import static com.alibaba.dubbo.common.Constants.QOS_PORT; -import static com.alibaba.dubbo.common.Constants.VALIDATION_KEY; - -/** - * RegistryProtocol - * - */ -public class RegistryProtocol implements Protocol { - - private final static Logger logger = LoggerFactory.getLogger(RegistryProtocol.class); - private static RegistryProtocol INSTANCE; - private final Map overrideListeners = new ConcurrentHashMap(); - //To solve the problem of RMI repeated exposure port conflicts, the services that have been exposed are no longer exposed. - //providerurl <--> exporter - private final Map> bounds = new ConcurrentHashMap>(); - private Cluster cluster; - private Protocol protocol; - private RegistryFactory registryFactory; - private ProxyFactory proxyFactory; - - public RegistryProtocol() { - INSTANCE = this; - } - - public static RegistryProtocol getRegistryProtocol() { - if (INSTANCE == null) { - ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(Constants.REGISTRY_PROTOCOL); // load - } - return INSTANCE; - } - - //Filter the parameters that do not need to be output in url(Starting with .) - private static String[] getFilteredKeys(URL url) { - Map params = url.getParameters(); - if (params != null && !params.isEmpty()) { - List filteredKeys = new ArrayList(); - for (Map.Entry entry : params.entrySet()) { - if (entry != null && entry.getKey() != null && entry.getKey().startsWith(Constants.HIDE_KEY_PREFIX)) { - filteredKeys.add(entry.getKey()); - } - } - return filteredKeys.toArray(new String[filteredKeys.size()]); - } else { - return new String[]{}; - } - } - - public void setCluster(Cluster cluster) { - this.cluster = cluster; - } - - public void setProtocol(Protocol protocol) { - this.protocol = protocol; - } - - public void setRegistryFactory(RegistryFactory registryFactory) { - this.registryFactory = registryFactory; - } - - public void setProxyFactory(ProxyFactory proxyFactory) { - this.proxyFactory = proxyFactory; - } - - @Override - public int getDefaultPort() { - return 9090; - } - - public Map getOverrideListeners() { - return overrideListeners; - } - - public void register(URL registryUrl, URL registedProviderUrl) { - Registry registry = registryFactory.getRegistry(registryUrl); - registry.register(registedProviderUrl); - } - - @Override - public Exporter export(final Invoker originInvoker) throws RpcException { - //export invoker - final ExporterChangeableWrapper exporter = doLocalExport(originInvoker); - - URL registryUrl = getRegistryUrl(originInvoker); - - //registry provider - final Registry registry = getRegistry(originInvoker); - final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); - - //to judge to delay publish whether or not - boolean register = registedProviderUrl.getParameter("register", true); - - ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl); - - if (register) { - register(registryUrl, registedProviderUrl); - ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true); - } - - // Subscribe the override data - // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover. - final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl); - final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); - overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); - registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); - //Ensure that a new exporter instance is returned every time export - return new DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl); - } - - @SuppressWarnings("unchecked") - private ExporterChangeableWrapper doLocalExport(final Invoker originInvoker) { - String key = getCacheKey(originInvoker); - ExporterChangeableWrapper exporter = (ExporterChangeableWrapper) bounds.get(key); - if (exporter == null) { - synchronized (bounds) { - exporter = (ExporterChangeableWrapper) bounds.get(key); - if (exporter == null) { - final Invoker invokerDelegete = new InvokerDelegete(originInvoker, getProviderUrl(originInvoker)); - exporter = new ExporterChangeableWrapper((Exporter) protocol.export(invokerDelegete), originInvoker); - bounds.put(key, exporter); - } - } - } - return exporter; - } - - /** - * Reexport the invoker of the modified url - * - * @param originInvoker - * @param newInvokerUrl - */ - @SuppressWarnings("unchecked") - private void doChangeLocalExport(final Invoker originInvoker, URL newInvokerUrl) { - String key = getCacheKey(originInvoker); - final ExporterChangeableWrapper exporter = (ExporterChangeableWrapper) bounds.get(key); - if (exporter == null) { - logger.warn(new IllegalStateException("error state, exporter should not be null")); - } else { - final Invoker invokerDelegete = new InvokerDelegete(originInvoker, newInvokerUrl); - exporter.setExporter(protocol.export(invokerDelegete)); - } - } - - /** - * Get an instance of registry based on the address of invoker - * - * @param originInvoker - * @return - */ - private Registry getRegistry(final Invoker originInvoker) { - URL registryUrl = getRegistryUrl(originInvoker); - return registryFactory.getRegistry(registryUrl); - } - - private URL getRegistryUrl(Invoker originInvoker) { - URL registryUrl = originInvoker.getUrl(); - if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) { - String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY); - registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY); - } - return registryUrl; - } - - - /** - * Return the url that is registered to the registry and filter the url parameter once - * - * @param originInvoker - * @return - */ - private URL getRegistedProviderUrl(final Invoker originInvoker) { - URL providerUrl = getProviderUrl(originInvoker); - //The address you see at the registry - final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl)) - .removeParameter(Constants.MONITOR_KEY) - .removeParameter(Constants.BIND_IP_KEY) - .removeParameter(Constants.BIND_PORT_KEY) - .removeParameter(QOS_ENABLE) - .removeParameter(QOS_PORT) - .removeParameter(ACCEPT_FOREIGN_IP) - .removeParameter(VALIDATION_KEY) - .removeParameter(INTERFACES); - return registedProviderUrl; - } - - private URL getSubscribedOverrideUrl(URL registedProviderUrl) { - return registedProviderUrl.setProtocol(Constants.PROVIDER_PROTOCOL) - .addParameters(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY, - Constants.CHECK_KEY, String.valueOf(false)); - } - - /** - * Get the address of the providerUrl through the url of the invoker - * - * @param origininvoker - * @return - */ - private URL getProviderUrl(final Invoker origininvoker) { - String export = origininvoker.getUrl().getParameterAndDecoded(Constants.EXPORT_KEY); - if (export == null || export.length() == 0) { - throw new IllegalArgumentException("The registry export url is null! registry: " + origininvoker.getUrl()); - } - - URL providerUrl = URL.valueOf(export); - return providerUrl; - } - - /** - * Get the key cached in bounds by invoker - * - * @param originInvoker - * @return - */ - private String getCacheKey(final Invoker originInvoker) { - URL providerUrl = getProviderUrl(originInvoker); - String key = providerUrl.removeParameters("dynamic", "enabled").toFullString(); - return key; - } - - @Override - @SuppressWarnings("unchecked") - public Invoker refer(Class type, URL url) throws RpcException { - url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY); - Registry registry = registryFactory.getRegistry(url); - if (RegistryService.class.equals(type)) { - return proxyFactory.getInvoker((T) registry, type, url); - } - - // group="a,b" or group="*" - Map qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); - String group = qs.get(Constants.GROUP_KEY); - if (group != null && group.length() > 0) { - if ((Constants.COMMA_SPLIT_PATTERN.split(group)).length > 1 - || "*".equals(group)) { - return doRefer(getMergeableCluster(), registry, type, url); - } - } - return doRefer(cluster, registry, type, url); - } - - private Cluster getMergeableCluster() { - return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("mergeable"); - } - - private Invoker doRefer(Cluster cluster, Registry registry, Class type, URL url) { - RegistryDirectory directory = new RegistryDirectory(type, url); - directory.setRegistry(registry); - directory.setProtocol(protocol); - // all attributes of REFER_KEY - Map parameters = new HashMap(directory.getUrl().getParameters()); - URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters); - if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) - && url.getParameter(Constants.REGISTER_KEY, true)) { - registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY, - Constants.CHECK_KEY, String.valueOf(false))); - } - directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, - Constants.PROVIDERS_CATEGORY - + "," + Constants.CONFIGURATORS_CATEGORY - + "," + Constants.ROUTERS_CATEGORY)); - - Invoker invoker = cluster.join(directory); - ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory); - return invoker; - } - - @Override - public void destroy() { - List> exporters = new ArrayList>(bounds.values()); - for (Exporter exporter : exporters) { - exporter.unexport(); - } - bounds.clear(); - } - - public static class InvokerDelegete extends InvokerWrapper { - private final Invoker invoker; - - /** - * @param invoker - * @param url invoker.getUrl return this value - */ - public InvokerDelegete(Invoker invoker, URL url) { - super(invoker, url); - this.invoker = invoker; - } - - public Invoker getInvoker() { - if (invoker instanceof InvokerDelegete) { - return ((InvokerDelegete) invoker).getInvoker(); - } else { - return invoker; - } - } - } - - /** - * Reexport: the exporter destroy problem in protocol - * 1.Ensure that the exporter returned by registryprotocol can be normal destroyed - * 2.No need to re-register to the registry after notify - * 3.The invoker passed by the export method , would better to be the invoker of exporter - */ - private class OverrideListener implements NotifyListener { - - private final URL subscribeUrl; - private final Invoker originInvoker; - - public OverrideListener(URL subscribeUrl, Invoker originalInvoker) { - this.subscribeUrl = subscribeUrl; - this.originInvoker = originalInvoker; - } - - /** - * @param urls The list of registered information , is always not empty, The meaning is the same as the return value of {@link com.alibaba.dubbo.registry.RegistryService#lookup(URL)}. - */ - @Override - public synchronized void notify(List urls) { - logger.debug("original override urls: " + urls); - List matchedUrls = getMatchedUrls(urls, subscribeUrl); - logger.debug("subscribe url: " + subscribeUrl + ", override urls: " + matchedUrls); - // No matching results - if (matchedUrls.isEmpty()) { - return; - } - - List configurators = RegistryDirectory.toConfigurators(matchedUrls); - - final Invoker invoker; - if (originInvoker instanceof InvokerDelegete) { - invoker = ((InvokerDelegete) originInvoker).getInvoker(); - } else { - invoker = originInvoker; - } - //The origin invoker - URL originUrl = RegistryProtocol.this.getProviderUrl(invoker); - String key = getCacheKey(originInvoker); - ExporterChangeableWrapper exporter = bounds.get(key); - if (exporter == null) { - logger.warn(new IllegalStateException("error state, exporter should not be null")); - return; - } - //The current, may have been merged many times - URL currentUrl = exporter.getInvoker().getUrl(); - //Merged with this configuration - URL newUrl = getConfigedInvokerUrl(configurators, originUrl); - if (!currentUrl.equals(newUrl)) { - RegistryProtocol.this.doChangeLocalExport(originInvoker, newUrl); - logger.info("exported provider url changed, origin url: " + originUrl + ", old export url: " + currentUrl + ", new export url: " + newUrl); - } - } - - private List getMatchedUrls(List configuratorUrls, URL currentSubscribe) { - List result = new ArrayList(); - for (URL url : configuratorUrls) { - URL overrideUrl = url; - // Compatible with the old version - if (url.getParameter(Constants.CATEGORY_KEY) == null - && Constants.OVERRIDE_PROTOCOL.equals(url.getProtocol())) { - overrideUrl = url.addParameter(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY); - } - - // Check whether url is to be applied to the current service - if (UrlUtils.isMatch(currentSubscribe, overrideUrl)) { - result.add(url); - } - } - return result; - } - - //Merge the urls of configurators - private URL getConfigedInvokerUrl(List configurators, URL url) { - for (Configurator configurator : configurators) { - url = configurator.configure(url); - } - return url; - } - } - - /** - * exporter proxy, establish the corresponding relationship between the returned exporter and the exporter exported by the protocol, and can modify the relationship at the time of override. - * - * @param - */ - private class ExporterChangeableWrapper implements Exporter { - - private final Invoker originInvoker; - private Exporter exporter; - - public ExporterChangeableWrapper(Exporter exporter, Invoker originInvoker) { - this.exporter = exporter; - this.originInvoker = originInvoker; - } - - public Invoker getOriginInvoker() { - return originInvoker; - } - - @Override - public Invoker getInvoker() { - return exporter.getInvoker(); - } - - public void setExporter(Exporter exporter) { - this.exporter = exporter; - } - - @Override - public void unexport() { - String key = getCacheKey(this.originInvoker); - bounds.remove(key); - exporter.unexport(); - } - } - - static private class DestroyableExporter implements Exporter { - - public static final ExecutorService executor = Executors.newSingleThreadExecutor(new NamedThreadFactory("Exporter-Unexport", true)); - - private Exporter exporter; - private Invoker originInvoker; - private URL subscribeUrl; - private URL registerUrl; - - public DestroyableExporter(Exporter exporter, Invoker originInvoker, URL subscribeUrl, URL registerUrl) { - this.exporter = exporter; - this.originInvoker = originInvoker; - this.subscribeUrl = subscribeUrl; - this.registerUrl = registerUrl; - } - - @Override - public Invoker getInvoker() { - return exporter.getInvoker(); - } - - @Override - public void unexport() { - Registry registry = RegistryProtocol.INSTANCE.getRegistry(originInvoker); - try { - registry.unregister(registerUrl); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - try { - NotifyListener listener = RegistryProtocol.INSTANCE.overrideListeners.remove(subscribeUrl); - registry.unsubscribe(subscribeUrl, listener); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - - executor.submit(new Runnable() { - @Override - public void run() { - try { - int timeout = ConfigUtils.getServerShutdownTimeout(); - if (timeout > 0) { - logger.info("Waiting " + timeout + "ms for registry to notify all consumers before unexport. Usually, this is called when you use dubbo API"); - Thread.sleep(timeout); - } - exporter.unexport(); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - }); - } - } -} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java deleted file mode 100644 index 8d8f28445df..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/ExchangeHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.exchange; - -import com.alibaba.dubbo.remoting.ChannelHandler; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.telnet.TelnetHandler; - -import java.util.concurrent.CompletableFuture; - -/** - * ExchangeHandler. (API, Prototype, ThreadSafe) - */ -public interface ExchangeHandler extends ChannelHandler, TelnetHandler { - - /** - * reply. - * - * @param channel - * @param request - * @return response - * @throws RemotingException - */ - CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException; - -} \ No newline at end of file diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java deleted file mode 100644 index 8dd1d7a3a94..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.exchange.support; - -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; - -import java.util.concurrent.CompletableFuture; - -/** - * ExchangeHandlerAdapter - */ -public abstract class ExchangeHandlerAdapter extends TelnetHandlerAdapter implements ExchangeHandler { - - @Override - public CompletableFuture reply(ExchangeChannel channel, Object msg) throws RemotingException { - return null; - } - -} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java deleted file mode 100644 index 1e455884dfc..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.exchange.support; - -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.ChannelHandler; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.telnet.TelnetHandler; -import com.alibaba.dubbo.remoting.telnet.support.TelnetHandlerAdapter; -import com.alibaba.dubbo.remoting.transport.ChannelHandlerDispatcher; - -import java.util.concurrent.CompletableFuture; - -/** - * ExchangeHandlerDispatcher - */ -public class ExchangeHandlerDispatcher implements ExchangeHandler { - - private final ReplierDispatcher replierDispatcher; - - private final ChannelHandlerDispatcher handlerDispatcher; - - private final TelnetHandler telnetHandler; - - public ExchangeHandlerDispatcher() { - replierDispatcher = new ReplierDispatcher(); - handlerDispatcher = new ChannelHandlerDispatcher(); - telnetHandler = new TelnetHandlerAdapter(); - } - - public ExchangeHandlerDispatcher(Replier replier) { - replierDispatcher = new ReplierDispatcher(replier); - handlerDispatcher = new ChannelHandlerDispatcher(); - telnetHandler = new TelnetHandlerAdapter(); - } - - public ExchangeHandlerDispatcher(ChannelHandler... handlers) { - replierDispatcher = new ReplierDispatcher(); - handlerDispatcher = new ChannelHandlerDispatcher(handlers); - telnetHandler = new TelnetHandlerAdapter(); - } - - public ExchangeHandlerDispatcher(Replier replier, ChannelHandler... handlers) { - replierDispatcher = new ReplierDispatcher(replier); - handlerDispatcher = new ChannelHandlerDispatcher(handlers); - telnetHandler = new TelnetHandlerAdapter(); - } - - public ExchangeHandlerDispatcher addChannelHandler(ChannelHandler handler) { - handlerDispatcher.addChannelHandler(handler); - return this; - } - - public ExchangeHandlerDispatcher removeChannelHandler(ChannelHandler handler) { - handlerDispatcher.removeChannelHandler(handler); - return this; - } - - public ExchangeHandlerDispatcher addReplier(Class type, Replier replier) { - replierDispatcher.addReplier(type, replier); - return this; - } - - public ExchangeHandlerDispatcher removeReplier(Class type) { - replierDispatcher.removeReplier(type); - return this; - } - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - return CompletableFuture.completedFuture(((Replier) replierDispatcher).reply(channel, request)); - } - - @Override - public void connected(Channel channel) { - handlerDispatcher.connected(channel); - } - - @Override - public void disconnected(Channel channel) { - handlerDispatcher.disconnected(channel); - } - - @Override - public void sent(Channel channel, Object message) { - handlerDispatcher.sent(channel, message); - } - - @Override - public void received(Channel channel, Object message) { - handlerDispatcher.received(channel, message); - } - - @Override - public void caught(Channel channel, Throwable exception) { - handlerDispatcher.caught(channel, exception); - } - - @Override - public String telnet(Channel channel, String message) throws RemotingException { - return telnetHandler.telnet(channel, message); - } - -} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java deleted file mode 100644 index 873d4adb3d0..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.exchange.support.header; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.Version; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.ChannelHandler; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.Request; -import com.alibaba.dubbo.remoting.exchange.Response; -import com.alibaba.dubbo.remoting.exchange.ResponseFuture; -import com.alibaba.dubbo.remoting.exchange.support.DefaultFuture; - -import java.net.InetSocketAddress; - -/** - * ExchangeReceiver - */ -final class HeaderExchangeChannel implements ExchangeChannel { - - private static final Logger logger = LoggerFactory.getLogger(HeaderExchangeChannel.class); - - private static final String CHANNEL_KEY = HeaderExchangeChannel.class.getName() + ".CHANNEL"; - - private final Channel channel; - - private volatile boolean closed = false; - - HeaderExchangeChannel(Channel channel) { - if (channel == null) { - throw new IllegalArgumentException("channel == null"); - } - this.channel = channel; - } - - static HeaderExchangeChannel getOrAddChannel(Channel ch) { - if (ch == null) { - return null; - } - HeaderExchangeChannel ret = (HeaderExchangeChannel) ch.getAttribute(CHANNEL_KEY); - if (ret == null) { - ret = new HeaderExchangeChannel(ch); - if (ch.isConnected()) { - ch.setAttribute(CHANNEL_KEY, ret); - } - } - return ret; - } - - static void removeChannelIfDisconnected(Channel ch) { - if (ch != null && !ch.isConnected()) { - ch.removeAttribute(CHANNEL_KEY); - } - } - - @Override - public void send(Object message) throws RemotingException { - send(message, false); - } - - @Override - public void send(Object message, boolean sent) throws RemotingException { - if (closed) { - throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The channel " + this + " is closed!"); - } - if (message instanceof Request - || message instanceof Response - || message instanceof String) { - channel.send(message, sent); - } else { - Request request = new Request(); - request.setVersion(Version.getProtocolVersion()); - request.setTwoWay(false); - request.setData(message); - channel.send(request, sent); - } - } - - @Override - public ResponseFuture request(Object request) throws RemotingException { - return request(request, channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); - } - - @Override - public ResponseFuture 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!"); - } - // create request. - Request req = new Request(); - req.setVersion(Version.getProtocolVersion()); - req.setTwoWay(true); - req.setData(request); - DefaultFuture future = new DefaultFuture(channel, req, timeout); - try { - channel.send(req); - } catch (RemotingException e) { - future.cancel(); - throw e; - } - return future; - } - - @Override - public boolean isClosed() { - return closed; - } - - @Override - public void close() { - try { - channel.close(); - } catch (Throwable e) { - logger.warn(e.getMessage(), e); - } - } - - // graceful close - @Override - public void close(int timeout) { - if (closed) { - return; - } - closed = true; - if (timeout > 0) { - long start = System.currentTimeMillis(); - while (DefaultFuture.hasFuture(channel) - && System.currentTimeMillis() - start < timeout) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - logger.warn(e.getMessage(), e); - } - } - } - close(); - } - - @Override - public void startClose() { - channel.startClose(); - } - - @Override - public InetSocketAddress getLocalAddress() { - return channel.getLocalAddress(); - } - - @Override - public InetSocketAddress getRemoteAddress() { - return channel.getRemoteAddress(); - } - - @Override - public URL getUrl() { - return channel.getUrl(); - } - - @Override - public boolean isConnected() { - return channel.isConnected(); - } - - @Override - public ChannelHandler getChannelHandler() { - return channel.getChannelHandler(); - } - - @Override - public ExchangeHandler getExchangeHandler() { - return (ExchangeHandler) channel.getChannelHandler(); - } - - @Override - public Object getAttribute(String key) { - return channel.getAttribute(key); - } - - @Override - public void setAttribute(String key, Object value) { - channel.setAttribute(key, value); - } - - @Override - public void removeAttribute(String key) { - channel.removeAttribute(key); - } - - @Override - public boolean hasAttribute(String key) { - return channel.hasAttribute(key); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((channel == null) ? 0 : channel.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - HeaderExchangeChannel other = (HeaderExchangeChannel) obj; - if (channel == null) { - if (other.channel != null) return false; - } else if (!channel.equals(other.channel)) return false; - return true; - } - - @Override - public String toString() { - return channel.toString(); - } - -} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java deleted file mode 100644 index 81139bc68a1..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.exchange.support.header; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.NetUtils; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.ChannelHandler; -import com.alibaba.dubbo.remoting.ExecutionException; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.Request; -import com.alibaba.dubbo.remoting.exchange.Response; -import com.alibaba.dubbo.remoting.exchange.support.DefaultFuture; -import com.alibaba.dubbo.remoting.transport.ChannelHandlerDelegate; - -import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; - -/** - * ExchangeReceiver - */ -public class HeaderExchangeHandler implements ChannelHandlerDelegate { - - protected static final Logger logger = LoggerFactory.getLogger(HeaderExchangeHandler.class); - - public static String KEY_READ_TIMESTAMP = HeartbeatHandler.KEY_READ_TIMESTAMP; - - public static String KEY_WRITE_TIMESTAMP = HeartbeatHandler.KEY_WRITE_TIMESTAMP; - - private final ExchangeHandler handler; - - public HeaderExchangeHandler(ExchangeHandler handler) { - if (handler == null) { - throw new IllegalArgumentException("handler == null"); - } - this.handler = handler; - } - - static void handleResponse(Channel channel, Response response) throws RemotingException { - if (response != null && !response.isHeartbeat()) { - DefaultFuture.received(channel, response); - } - } - - private static boolean isClientSide(Channel channel) { - InetSocketAddress address = channel.getRemoteAddress(); - URL url = channel.getUrl(); - return url.getPort() == address.getPort() && - NetUtils.filterLocalHost(url.getIp()) - .equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress())); - } - - void handlerEvent(Channel channel, Request req) throws RemotingException { - if (req.getData() != null && req.getData().equals(Request.READONLY_EVENT)) { - channel.setAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY, Boolean.TRUE); - } - } - - void handleRequest(ExchangeChannel channel, Request req) throws RemotingException { - Response res = new Response(req.getId(), req.getVersion()); - if (req.isBroken()) { - Object data = req.getData(); - - String msg; - if (data == null) msg = null; - else if (data instanceof Throwable) msg = StringUtils.toString((Throwable) data); - else msg = data.toString(); - res.setErrorMessage("Fail to decode request due to: " + msg); - res.setStatus(Response.BAD_REQUEST); - - channel.send(res); - return; - } - // find handler by message class. - Object msg = req.getData(); - try { - // handle data. - CompletableFuture future = handler.reply(channel, msg); - if (future.isDone()) { - res.setStatus(Response.OK); - res.setResult(future.get()); - channel.send(res); - return; - } - future.whenComplete((result, t) -> { - try { - if (t == null) { - res.setStatus(Response.OK); - res.setResult(result); - } else { - res.setStatus(Response.SERVICE_ERROR); - res.setErrorMessage(StringUtils.toString(t)); - } - channel.send(res); - } catch (RemotingException e) { - logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e); - } finally { - // HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - }); - } catch (Throwable e) { - res.setStatus(Response.SERVICE_ERROR); - res.setErrorMessage(StringUtils.toString(e)); - channel.send(res); - } - } - - @Override - public void connected(Channel channel) throws RemotingException { - channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); - channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); - ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); - try { - handler.connected(exchangeChannel); - } finally { - HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - } - - @Override - public void disconnected(Channel channel) throws RemotingException { - channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); - channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); - ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); - try { - handler.disconnected(exchangeChannel); - } finally { - HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - } - - @Override - public void sent(Channel channel, Object message) throws RemotingException { - Throwable exception = null; - try { - channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); - ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); - try { - handler.sent(exchangeChannel, message); - } finally { - HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - } catch (Throwable t) { - exception = t; - } - if (message instanceof Request) { - Request request = (Request) message; - DefaultFuture.sent(channel, request); - } - if (exception != null) { - if (exception instanceof RuntimeException) { - throw (RuntimeException) exception; - } else if (exception instanceof RemotingException) { - throw (RemotingException) exception; - } else { - throw new RemotingException(channel.getLocalAddress(), channel.getRemoteAddress(), - exception.getMessage(), exception); - } - } - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis()); - ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); - try { - if (message instanceof Request) { - // handle request. - Request request = (Request) message; - if (request.isEvent()) { - handlerEvent(channel, request); - } else { - if (request.isTwoWay()) { - handleRequest(exchangeChannel, request); - } else { - handler.received(exchangeChannel, request.getData()); - } - } - } else if (message instanceof Response) { - handleResponse(channel, (Response) message); - } else if (message instanceof String) { - if (isClientSide(channel)) { - Exception e = new Exception("Dubbo client can not supported string message: " + message + " in channel: " + channel + ", url: " + channel.getUrl()); - logger.error(e.getMessage(), e); - } else { - String echo = handler.telnet(channel, (String) message); - if (echo != null && echo.length() > 0) { - channel.send(echo); - } - } - } else { - handler.received(exchangeChannel, message); - } - } finally { - HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - } - - @Override - public void caught(Channel channel, Throwable exception) throws RemotingException { - if (exception instanceof ExecutionException) { - ExecutionException e = (ExecutionException) exception; - Object msg = e.getRequest(); - if (msg instanceof Request) { - Request req = (Request) msg; - if (req.isTwoWay() && !req.isHeartbeat()) { - Response res = new Response(req.getId(), req.getVersion()); - res.setStatus(Response.SERVER_ERROR); - res.setErrorMessage(StringUtils.toString(e)); - channel.send(res); - return; - } - } - } - ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel); - try { - handler.caught(exchangeChannel, exception); - } finally { - HeaderExchangeChannel.removeChannelIfDisconnected(channel); - } - } - - @Override - public ChannelHandler getHandler() { - if (handler instanceof ChannelHandlerDelegate) { - return ((ChannelHandlerDelegate) handler).getHandler(); - } else { - return handler; - } - } -} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java index 5849a7fd2fb..e2f0f42c8b1 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java @@ -33,4 +33,4 @@ public CompletableFuture reply(ExchangeChannel channel, Object msg) thro return null; } -} +} \ No newline at end of file diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java index 536e2a4abdf..21108132ce1 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java @@ -36,6 +36,7 @@ import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; + /** * ExchangeReceiver */ @@ -102,7 +103,7 @@ void handleRequest(ExchangeChannel channel, Request req) throws RemotingExceptio channel.send(res); return; } - future.whenCompleteAsync((result, t) -> { + future.whenComplete((result, t) -> { try { if (t == null) { res.setStatus(Response.OK); diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java deleted file mode 100644 index e021df0c4e9..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/PerformanceServerTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeServer; -import com.alibaba.dubbo.remoting.exchange.Exchangers; -import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import com.alibaba.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher; - -import junit.framework.TestCase; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -/** - * PerformanceServer - *

- * mvn clean test -Dtest=*PerformanceServerTest -Dport=9911 - */ -public class PerformanceServerTest extends TestCase { - - private static final Logger logger = LoggerFactory.getLogger(PerformanceServerTest.class); - private static ExchangeServer server = null; - - private static void restartServer(int times, int alive, int sleep) throws Exception { - if (server != null && !server.isClosed()) { - server.close(); - Thread.sleep(100); - } - - for (int i = 0; i < times; i++) { - logger.info("restart times:" + i); - server = statServer(); - if (alive > 0) Thread.sleep(alive); - server.close(); - if (sleep > 0) Thread.sleep(sleep); - } - - server = statServer(); - } - - private static ExchangeServer statServer() throws Exception { - final int port = PerformanceUtils.getIntProperty("port", 9911); - final String transporter = PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER); - final String serialization = PerformanceUtils.getProperty(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); - final String threadpool = PerformanceUtils.getProperty(Constants.THREADPOOL_KEY, Constants.DEFAULT_THREADPOOL); - final int threads = PerformanceUtils.getIntProperty(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); - final int iothreads = PerformanceUtils.getIntProperty(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS); - final int buffer = PerformanceUtils.getIntProperty(Constants.BUFFER_KEY, Constants.DEFAULT_BUFFER_SIZE); - final String channelHandler = PerformanceUtils.getProperty(Constants.DISPATCHER_KEY, ExecutionDispatcher.NAME); - - - // Start server - ExchangeServer server = Exchangers.bind("exchange://0.0.0.0:" + port + "?transporter=" - + transporter + "&serialization=" - + serialization + "&threadpool=" + threadpool - + "&threads=" + threads + "&iothreads=" + iothreads + "&buffer=" + buffer + "&channel.handler=" + channelHandler, new ExchangeHandlerAdapter() { - public String telnet(Channel channel, String message) throws RemotingException { - return "echo: " + message + "\r\ntelnet> "; - } - - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - if ("environment".equals(request)) { - return CompletableFuture.completedFuture(PerformanceUtils.getEnvironment()); - } - if ("scene".equals(request)) { - List scene = new ArrayList(); - scene.add("Transporter: " + transporter); - scene.add("Service Threads: " + threads); - return CompletableFuture.completedFuture(scene); - } - return CompletableFuture.completedFuture(request); - } - }); - - return server; - } - - private static ExchangeServer statTelnetServer(int port) throws Exception { - // Start server - ExchangeServer telnetserver = Exchangers.bind("exchange://0.0.0.0:" + port, new ExchangeHandlerAdapter() { - public String telnet(Channel channel, String message) throws RemotingException { - if (message.equals("help")) { - return "support cmd: \r\n\tstart \r\n\tstop \r\n\tshutdown \r\n\trestart times [alive] [sleep] \r\ntelnet>"; - } else if (message.equals("stop")) { - logger.info("server closed:" + server); - server.close(); - return "stop server\r\ntelnet>"; - } else if (message.startsWith("start")) { - try { - restartServer(0, 0, 0); - } catch (Exception e) { - e.printStackTrace(); - } - return "start server\r\ntelnet>"; - } else if (message.startsWith("shutdown")) { - System.exit(0); - return "start server\r\ntelnet>"; - } else if (message.startsWith("channels")) { - return "server.getExchangeChannels():" + server.getExchangeChannels().size() + "\r\ntelnet>"; - } else if (message.startsWith("restart ")) { //r times [sleep] r 10 or r 10 100 - String[] args = message.split(" "); - int times = Integer.parseInt(args[1]); - int alive = args.length > 2 ? Integer.parseInt(args[2]) : 0; - int sleep = args.length > 3 ? Integer.parseInt(args[3]) : 100; - try { - restartServer(times, alive, sleep); - } catch (Exception e) { - e.printStackTrace(); - } - - return "restart server,times:" + times + " stop alive time: " + alive + ",sleep time: " + sleep + " usage:r times [alive] [sleep] \r\ntelnet>"; - } else { - return "echo: " + message + "\r\ntelnet> "; - } - - } - }); - - return telnetserver; - } - - @Test - public void testServer() throws Exception { - // Read port from property - if (PerformanceUtils.getProperty("port", null) == null) { - logger.warn("Please set -Dport=9911"); - return; - } - final int port = PerformanceUtils.getIntProperty("port", 9911); - final boolean telnet = PerformanceUtils.getBooleanProperty("telnet", true); - if (telnet) statTelnetServer(port + 1); - server = statServer(); - - synchronized (PerformanceServerTest.class) { - while (true) { - try { - PerformanceServerTest.class.wait(); - } catch (InterruptedException e) { - } - } - } - } - -} \ No newline at end of file diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java deleted file mode 100644 index ff533098ada..00000000000 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/handler/HeaderExchangeHandlerTest.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.remoting.handler; - - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.Request; -import com.alibaba.dubbo.remoting.exchange.Response; -import com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; - -//TODO response test -public class HeaderExchangeHandlerTest { - - @Test - public void test_received_request_oneway() throws RemotingException { - final Channel mchannel = new MockedChannel(); - - final Person requestdata = new Person("charles"); - Request request = new Request(); - request.setTwoWay(false); - request.setData(requestdata); - - ExchangeHandler exhandler = new MockedExchangeHandler() { - @Override - public void received(Channel channel, Object message) throws RemotingException { - Assert.assertEquals(requestdata, message); - } - }; - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(exhandler); - hexhandler.received(mchannel, request); - } - - @Test - public void test_received_request_twoway() throws RemotingException { - final Person requestdata = new Person("charles"); - final Request request = new Request(); - request.setTwoWay(true); - request.setData(requestdata); - - final AtomicInteger count = new AtomicInteger(0); - final Channel mchannel = new MockedChannel() { - @Override - public void send(Object message) throws RemotingException { - Response res = (Response) message; - Assert.assertEquals(request.getId(), res.getId()); - Assert.assertEquals(request.getVersion(), res.getVersion()); - Assert.assertEquals(Response.OK, res.getStatus()); - Assert.assertEquals(requestdata, res.getResult()); - Assert.assertEquals(null, res.getErrorMessage()); - count.incrementAndGet(); - } - }; - ExchangeHandler exhandler = new MockedExchangeHandler() { - @Override - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - return CompletableFuture.completedFuture(request); - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - Assert.fail(); - } - }; - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(exhandler); - hexhandler.received(mchannel, request); - Assert.assertEquals(1, count.get()); - } - - @Test(expected = IllegalArgumentException.class) - public void test_received_request_twoway_error_nullhandler() throws RemotingException { - new HeaderExchangeHandler(null); - } - - @Test - public void test_received_request_twoway_error_reply() throws RemotingException { - final Person requestdata = new Person("charles"); - final Request request = new Request(); - request.setTwoWay(true); - request.setData(requestdata); - - final AtomicInteger count = new AtomicInteger(0); - final Channel mchannel = new MockedChannel() { - @Override - public void send(Object message) throws RemotingException { - Response res = (Response) message; - Assert.assertEquals(request.getId(), res.getId()); - Assert.assertEquals(request.getVersion(), res.getVersion()); - Assert.assertEquals(Response.SERVICE_ERROR, res.getStatus()); - Assert.assertNull(res.getResult()); - Assert.assertTrue(res.getErrorMessage().contains(BizException.class.getName())); - count.incrementAndGet(); - } - }; - ExchangeHandler exhandler = new MockedExchangeHandler() { - @Override - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - throw new BizException(); - } - }; - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(exhandler); - hexhandler.received(mchannel, request); - Assert.assertEquals(1, count.get()); - } - - @Test - public void test_received_request_twoway_error_reqeustBroken() throws RemotingException { - final Request request = new Request(); - request.setTwoWay(true); - request.setData(new BizException()); - request.setBroken(true); - - final AtomicInteger count = new AtomicInteger(0); - final Channel mchannel = new MockedChannel() { - @Override - public void send(Object message) throws RemotingException { - Response res = (Response) message; - Assert.assertEquals(request.getId(), res.getId()); - Assert.assertEquals(request.getVersion(), res.getVersion()); - Assert.assertEquals(Response.BAD_REQUEST, res.getStatus()); - Assert.assertNull(res.getResult()); - Assert.assertTrue(res.getErrorMessage().contains(BizException.class.getName())); - count.incrementAndGet(); - } - }; - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(new MockedExchangeHandler()); - hexhandler.received(mchannel, request); - Assert.assertEquals(1, count.get()); - } - - @Test - public void test_received_request_event_readonly() throws RemotingException { - final Request request = new Request(); - request.setTwoWay(true); - request.setEvent(Request.READONLY_EVENT); - - final Channel mchannel = new MockedChannel(); - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(new MockedExchangeHandler()); - hexhandler.received(mchannel, request); - Assert.assertTrue(mchannel.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)); - } - - @Test - public void test_received_request_event_other_discard() throws RemotingException { - final Request request = new Request(); - request.setTwoWay(true); - request.setEvent("my event"); - - final Channel mchannel = new MockedChannel() { - @Override - public void send(Object message) throws RemotingException { - Assert.fail(); - } - }; - HeaderExchangeHandler hexhandler = new HeaderExchangeHandler(new MockedExchangeHandler() { - - @Override - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - Assert.fail(); - throw new RemotingException(channel, ""); - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - Assert.fail(); - throw new RemotingException(channel, ""); - } - }); - hexhandler.received(mchannel, request); - } - - private class BizException extends RuntimeException { - private static final long serialVersionUID = 1L; - } - - private class MockedExchangeHandler extends MockedChannelHandler implements ExchangeHandler { - - public String telnet(Channel channel, String message) throws RemotingException { - throw new UnsupportedOperationException(); - } - - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - throw new UnsupportedOperationException(); - } - } - - private class Person { - private String name; - - public Person(String name) { - super(); - this.name = name; - } - - @Override - public String toString() { - return "Person [name=" + name + "]"; - } - } -} diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java deleted file mode 100644 index 6265f2d23aa..00000000000 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/com/alibaba/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.dubbo.remoting.exchange.support.header; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeClient; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.ExchangeServer; -import com.alibaba.dubbo.remoting.exchange.Exchangers; -import com.alibaba.dubbo.remoting.transport.dispatcher.FakeChannelHandlers; - -import org.junit.Assert; -import org.junit.After; -import org.junit.Test; - -import java.util.concurrent.CompletableFuture; - -public class HeartbeatHandlerTest { - - private static final Logger logger = LoggerFactory.getLogger(HeartbeatHandlerTest.class); - - private ExchangeServer server; - private ExchangeClient client; - - @After - public void after() throws Exception { - if (client != null) { - client.close(); - client = null; - } - - if (server != null) { - server.close(); - server = null; - } - } - - @Test - public void testServerHeartbeat() throws Exception { - URL serverURL = URL.valueOf("header://localhost:55555"); - serverURL = serverURL.addParameter(Constants.HEARTBEAT_KEY, 1000); - TestHeartbeatHandler handler = new TestHeartbeatHandler(); - server = Exchangers.bind(serverURL, handler); - System.out.println("Server bind successfully"); - - FakeChannelHandlers.setTestingChannelHandlers(); - serverURL = serverURL.removeParameter(Constants.HEARTBEAT_KEY); - client = Exchangers.connect(serverURL); - Thread.sleep(10000); - Assert.assertTrue(handler.disconnectCount > 0); - System.out.println("disconnect count " + handler.disconnectCount); - } - - @Test - public void testHeartbeat() throws Exception { - URL serverURL = URL.valueOf("header://localhost:55555"); - serverURL = serverURL.addParameter(Constants.HEARTBEAT_KEY, 1000); - TestHeartbeatHandler handler = new TestHeartbeatHandler(); - server = Exchangers.bind(serverURL, handler); - System.out.println("Server bind successfully"); - - client = Exchangers.connect(serverURL); - Thread.sleep(10000); - System.err.println("++++++++++++++ disconnect count " + handler.disconnectCount); - System.err.println("++++++++++++++ connect count " + handler.connectCount); - Assert.assertTrue(handler.disconnectCount == 0); - Assert.assertTrue(handler.connectCount == 1); - } - - @Test - public void testClientHeartbeat() throws Exception { - FakeChannelHandlers.setTestingChannelHandlers(); - URL serverURL = URL.valueOf("header://localhost:55555"); - TestHeartbeatHandler handler = new TestHeartbeatHandler(); - server = Exchangers.bind(serverURL, handler); - System.out.println("Server bind successfully"); - - FakeChannelHandlers.resetChannelHandlers(); - serverURL = serverURL.addParameter(Constants.HEARTBEAT_KEY, 1000); - client = Exchangers.connect(serverURL); - Thread.sleep(10000); - Assert.assertTrue(handler.connectCount > 0); - System.out.println("connect count " + handler.connectCount); - } - - class TestHeartbeatHandler implements ExchangeHandler { - - public int disconnectCount = 0; - public int connectCount = 0; - - public CompletableFuture reply(ExchangeChannel channel, Object request) throws RemotingException { - return CompletableFuture.completedFuture(request); - } - - @Override - public void connected(Channel channel) throws RemotingException { - ++connectCount; - } - - @Override - public void disconnected(Channel channel) throws RemotingException { - ++disconnectCount; - } - - @Override - public void sent(Channel channel, Object message) throws RemotingException { - - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - logger.error(this.getClass().getSimpleName() + message.toString()); - } - - @Override - public void caught(Channel channel, Throwable exception) throws RemotingException { - exception.printStackTrace(); - } - - public String telnet(Channel channel, String message) throws RemotingException { - return message; - } - } - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java deleted file mode 100644 index ae5671ee11d..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContext.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import java.util.concurrent.CompletableFuture; - -public interface AsyncContext { - - CompletableFuture getInternalFuture(); - - void addListener(Runnable run); - - void write(Object value); - - boolean isAsyncStarted(); - - boolean stop(); - - void start(); - - void signalContextSwitch(); -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java deleted file mode 100644 index 2b360e69be1..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncContextImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; - -public class AsyncContextImpl implements AsyncContext { - private static final Logger logger = LoggerFactory.getLogger(AsyncContextImpl.class); - - private final AtomicBoolean started = new AtomicBoolean(false); - - private CompletableFuture future; - - public AsyncContextImpl() { - } - - public AsyncContextImpl(CompletableFuture future) { - this.future = future; - } - - @Override - public void addListener(Runnable run) { - - } - - @Override - public void write(Object value) { - if (stop()) { - if (value instanceof Throwable) { - // TODO check exception type like ExceptionFilter do. - future.completeExceptionally((Throwable) value); - } - future.complete(value); - } else { - throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); - } - } - - @Override - public boolean isAsyncStarted() { - return started.get(); - } - - @Override - public boolean stop() { - if (started.compareAndSet(true, false)) { -// future.cancel(true); - return true; - } - return false; - } - - @Override - public void start() { - this.started.set(true); - } - - @Override - public void signalContextSwitch() { - - } - - @Override - public CompletableFuture getInternalFuture() { - return future; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java deleted file mode 100644 index 9390da5b014..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AsyncRpcResult.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; - -/** - * - */ -public class AsyncRpcResult extends AbstractResult { - private static final Logger logger = LoggerFactory.getLogger(AsyncRpcResult.class); - - private Map attachments = new HashMap(); - - protected CompletableFuture valueFuture; - - protected CompletableFuture resultFuture; - - public AsyncRpcResult(CompletableFuture future) { - this(future, true); - } - - public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { - if (registerCallback) { - resultFuture = new CompletableFuture<>(); - /** - * 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, is Dubbo thread. - * 2. future complete after whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread calling complete, normally is 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); - } - resultFuture.complete(rpcResult); - }); - } - this.valueFuture = future; - } - - @Override - public Object getValue() { - return getRpcResult().getValue(); - } - - @Override - public Throwable getException() { - return getRpcResult().getException(); - } - - @Override - public boolean hasException() { - return getRpcResult().hasException(); - } - - @Override - public Object getResult() { - return getRpcResult().getResult(); - } - - public CompletableFuture getValueFuture() { - return valueFuture; - } - - public CompletableFuture getResultFuture() { - return resultFuture; - } - - public void setResultFuture(CompletableFuture resultFuture) { - this.resultFuture = resultFuture; - } - - public Result getRpcResult() { - Result result; - try { - result = resultFuture.get(); - } catch (Exception e) { - // This should never happen; - logger.error("", e); - result = new RpcResult(); - } - return result; - } - - @Override - public Object recreate() throws Throwable { - return valueFuture; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java deleted file mode 100644 index a1858e7dfee..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Result.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import java.io.Serializable; -import java.util.Map; - -/** - * RPC invoke result. (API, Prototype, NonThreadSafe) - * - * @serial Don't change the class name and package name. - * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation) - * @see com.alibaba.dubbo.rpc.RpcResult - */ -public interface Result extends Serializable { - - /** - * Get invoke result. - * - * @return result. if no result return null. - */ - Object getValue(); - - /** - * Get exception. - * - * @return exception. if no exception return null. - */ - Throwable getException(); - - /** - * Has exception. - * - * @return has exception. - */ - boolean hasException(); - - /** - * Recreate. - *

- * - * if (hasException()) { - * throw getException(); - * } else { - * return getValue(); - * } - * - * - * @return result. - * @throws if has exception throw it. - */ - Object recreate() throws Throwable; - - /** - * @see com.alibaba.dubbo.rpc.Result#getValue() - * @deprecated Replace to getValue() - */ - @Deprecated - Object getResult(); - - - /** - * get attachments. - * - * @return attachments. - */ - Map getAttachments(); - - /** - * Add the specified map to existing attachments in this instance. - * - * @param map - */ - public void addAttachments(Map map); - - /** - * Replace the existing attachments with the specified param. - * - * @param map - */ - public void setAttachments(Map map); - - /** - * get attachment by key. - * - * @return attachment value. - */ - String getAttachment(String key); - - /** - * get attachment by key with default value. - * - * @return attachment value. - */ - String getAttachment(String key, String defaultValue); - -} \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java deleted file mode 100644 index 540c9b79ea4..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.threadlocal.InternalThreadLocal; -import com.alibaba.dubbo.common.utils.NetUtils; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * Thread local context. (API, ThreadLocal, ThreadSafe) - *

- * Note: RpcContext is a temporary state holder. States in RpcContext changes every time when request is sent or received. - * For example: A invokes B, then B invokes C. On service B, RpcContext saves invocation info from A to B before B - * starts invoking C, and saves invocation info from B to C after B invokes C. - * - * @export - * @see com.alibaba.dubbo.rpc.filter.ContextFilter - */ -public class RpcContext { - - /** - * use internal thread local to improve performance - */ - private static final InternalThreadLocal LOCAL = new InternalThreadLocal() { - @Override - protected RpcContext initialValue() { - return new RpcContext(); - } - }; - private static final InternalThreadLocal SERVER_LOCAL = new InternalThreadLocal() { - @Override - protected RpcContext initialValue() { - return new RpcContext(); - } - }; - - private final Map attachments = new HashMap(); - private final Map values = new HashMap(); - private Future future; - - private List urls; - - private URL url; - - private String methodName; - - private Class[] parameterTypes; - - private Object[] arguments; - - private InetSocketAddress localAddress; - - private InetSocketAddress remoteAddress; - @Deprecated - private List> invokers; - @Deprecated - private Invoker invoker; - @Deprecated - private Invocation invocation; - - // now we don't use the 'values' map to hold these objects - // we want these objects to be as generic as possible - private Object request; - private Object response; - private AsyncContext asyncContext; - - protected RpcContext() { - } - - /** - * get server side context. - * - * @return server context - */ - public static RpcContext getServerContext() { - return SERVER_LOCAL.get(); - } - - /** - * remove server side context. - * - * @see com.alibaba.dubbo.rpc.filter.ContextFilter - */ - public static void removeServerContext() { - SERVER_LOCAL.remove(); - } - - /** - * get context. - * - * @return context - */ - public static RpcContext getContext() { - return LOCAL.get(); - } - - /** - * remove context. - * - * @see com.alibaba.dubbo.rpc.filter.ContextFilter - */ - public static void removeContext() { - LOCAL.remove(); - } - - /** - * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest - * - * @return null if the underlying protocol doesn't provide support for getting request - */ - public Object getRequest() { - return request; - } - - public void setRequest(Object request) { - this.request = request; - } - - /** - * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest - * - * @return null if the underlying protocol doesn't provide support for getting request or the request is not of the specified type - */ - @SuppressWarnings("unchecked") - public T getRequest(Class clazz) { - return (request != null && clazz.isAssignableFrom(request.getClass())) ? (T) request : null; - } - - /** - * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse - * - * @return null if the underlying protocol doesn't provide support for getting response - */ - public Object getResponse() { - return response; - } - - public void setResponse(Object response) { - this.response = response; - } - - /** - * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse - * - * @return null if the underlying protocol doesn't provide support for getting response or the response is not of the specified type - */ - @SuppressWarnings("unchecked") - public T getResponse(Class clazz) { - return (response != null && clazz.isAssignableFrom(response.getClass())) ? (T) response : null; - } - - /** - * is provider side. - * - * @return provider side. - */ - public boolean isProviderSide() { - return !isConsumerSide(); - } - - /** - * is consumer side. - * - * @return consumer side. - */ - public boolean isConsumerSide() { - return getUrl().getParameter(Constants.SIDE_KEY, Constants.PROVIDER_SIDE).equals(Constants.CONSUMER_SIDE); - } - - /** - * get CompletableFuture. - * - * @param - * @return future - */ - @SuppressWarnings("unchecked") - public CompletableFuture getCompletableFuture() { - return (CompletableFuture) future; - } - - /** - * get future. - * - * @param - * @return future - */ - @SuppressWarnings("unchecked") - public Future getFuture() { - return (Future) future; - } - - /** - * set future. - * - * @param future - */ - public void setFuture(Future future) { - this.future = future; - } - - public List getUrls() { - return urls == null && url != null ? (List) Arrays.asList(url) : urls; - } - - public void setUrls(List urls) { - this.urls = urls; - } - - public URL getUrl() { - return url; - } - - public void setUrl(URL url) { - this.url = url; - } - - /** - * get method name. - * - * @return method name. - */ - public String getMethodName() { - return methodName; - } - - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - /** - * get parameter types. - * - * @serial - */ - public Class[] getParameterTypes() { - return parameterTypes; - } - - public void setParameterTypes(Class[] parameterTypes) { - this.parameterTypes = parameterTypes; - } - - /** - * get arguments. - * - * @return arguments. - */ - public Object[] getArguments() { - return arguments; - } - - public void setArguments(Object[] arguments) { - this.arguments = arguments; - } - - /** - * set local address. - * - * @param host - * @param port - * @return context - */ - public RpcContext setLocalAddress(String host, int port) { - if (port < 0) { - port = 0; - } - this.localAddress = InetSocketAddress.createUnresolved(host, port); - return this; - } - - /** - * get local address. - * - * @return local address - */ - public InetSocketAddress getLocalAddress() { - return localAddress; - } - - /** - * set local address. - * - * @param address - * @return context - */ - public RpcContext setLocalAddress(InetSocketAddress address) { - this.localAddress = address; - return this; - } - - public String getLocalAddressString() { - return getLocalHost() + ":" + getLocalPort(); - } - - /** - * get local host name. - * - * @return local host name - */ - public String getLocalHostName() { - String host = localAddress == null ? null : localAddress.getHostName(); - if (host == null || host.length() == 0) { - return getLocalHost(); - } - return host; - } - - /** - * set remote address. - * - * @param host - * @param port - * @return context - */ - public RpcContext setRemoteAddress(String host, int port) { - if (port < 0) { - port = 0; - } - this.remoteAddress = InetSocketAddress.createUnresolved(host, port); - return this; - } - - /** - * get remote address. - * - * @return remote address - */ - public InetSocketAddress getRemoteAddress() { - return remoteAddress; - } - - /** - * set remote address. - * - * @param address - * @return context - */ - public RpcContext setRemoteAddress(InetSocketAddress address) { - this.remoteAddress = address; - return this; - } - - /** - * get remote address string. - * - * @return remote address string. - */ - public String getRemoteAddressString() { - return getRemoteHost() + ":" + getRemotePort(); - } - - /** - * get remote host name. - * - * @return remote host name - */ - public String getRemoteHostName() { - return remoteAddress == null ? null : remoteAddress.getHostName(); - } - - /** - * get local host. - * - * @return local host - */ - public String getLocalHost() { - String host = localAddress == null ? null : - localAddress.getAddress() == null ? localAddress.getHostName() - : NetUtils.filterLocalHost(localAddress.getAddress().getHostAddress()); - if (host == null || host.length() == 0) { - return NetUtils.getLocalHost(); - } - return host; - } - - /** - * get local port. - * - * @return port - */ - public int getLocalPort() { - return localAddress == null ? 0 : localAddress.getPort(); - } - - /** - * get remote host. - * - * @return remote host - */ - public String getRemoteHost() { - return remoteAddress == null ? null : - remoteAddress.getAddress() == null ? remoteAddress.getHostName() - : NetUtils.filterLocalHost(remoteAddress.getAddress().getHostAddress()); - } - - /** - * get remote port. - * - * @return remote port - */ - public int getRemotePort() { - return remoteAddress == null ? 0 : remoteAddress.getPort(); - } - - /** - * get attachment. - * - * @param key - * @return attachment - */ - public String getAttachment(String key) { - return attachments.get(key); - } - - /** - * set attachment. - * - * @param key - * @param value - * @return context - */ - public RpcContext setAttachment(String key, String value) { - if (value == null) { - attachments.remove(key); - } else { - attachments.put(key, value); - } - return this; - } - - /** - * remove attachment. - * - * @param key - * @return context - */ - public RpcContext removeAttachment(String key) { - attachments.remove(key); - return this; - } - - /** - * get attachments. - * - * @return attachments - */ - public Map getAttachments() { - return attachments; - } - - /** - * set attachments - * - * @param attachment - * @return context - */ - public RpcContext setAttachments(Map attachment) { - this.attachments.clear(); - if (attachment != null && attachment.size() > 0) { - this.attachments.putAll(attachment); - } - return this; - } - - public void clearAttachments() { - this.attachments.clear(); - } - - /** - * get values. - * - * @return values - */ - public Map get() { - return values; - } - - /** - * set value. - * - * @param key - * @param value - * @return context - */ - public RpcContext set(String key, Object value) { - if (value == null) { - values.remove(key); - } else { - values.put(key, value); - } - return this; - } - - /** - * remove value. - * - * @param key - * @return value - */ - public RpcContext remove(String key) { - values.remove(key); - return this; - } - - /** - * get value. - * - * @param key - * @return value - */ - public Object get(String key) { - return values.get(key); - } - - /** - * @deprecated Replace to isProviderSide() - */ - @Deprecated - public boolean isServerSide() { - return isProviderSide(); - } - - /** - * @deprecated Replace to isConsumerSide() - */ - @Deprecated - public boolean isClientSide() { - return isConsumerSide(); - } - - /** - * @deprecated Replace to getUrls() - */ - @Deprecated - @SuppressWarnings({"unchecked", "rawtypes"}) - public List> getInvokers() { - return invokers == null && invoker != null ? (List) Arrays.asList(invoker) : invokers; - } - - public RpcContext setInvokers(List> invokers) { - this.invokers = invokers; - if (invokers != null && !invokers.isEmpty()) { - List urls = new ArrayList(invokers.size()); - for (Invoker invoker : invokers) { - urls.add(invoker.getUrl()); - } - setUrls(urls); - } - return this; - } - - /** - * @deprecated Replace to getUrl() - */ - @Deprecated - public Invoker getInvoker() { - return invoker; - } - - public RpcContext setInvoker(Invoker invoker) { - this.invoker = invoker; - if (invoker != null) { - setUrl(invoker.getUrl()); - } - return this; - } - - /** - * @deprecated Replace to getMethodName(), getParameterTypes(), getArguments() - */ - @Deprecated - public Invocation getInvocation() { - return invocation; - } - - public RpcContext setInvocation(Invocation invocation) { - this.invocation = invocation; - if (invocation != null) { - setMethodName(invocation.getMethodName()); - setParameterTypes(invocation.getParameterTypes()); - setArguments(invocation.getArguments()); - } - return this; - } - - /** - * Async invocation. Timeout will be handled even if Future.get() is not called. - * - * @param callable - * @return get the return result from future.get() - */ - @SuppressWarnings("unchecked") - public Future asyncCall(Callable callable) { - try { - try { - setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString()); - final T o = callable.call(); - //local invoke will return directly - if (o != null) { - FutureTask f = new FutureTask(new Callable() { - @Override - public T call() throws Exception { - return o; - } - }); - f.run(); - return f; - } else { - - } - } catch (Exception e) { - throw new RpcException(e); - } finally { - removeAttachment(Constants.ASYNC_KEY); - } - } catch (final RpcException e) { - return new Future() { - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return true; - } - - @Override - public T get() throws InterruptedException, ExecutionException { - throw new ExecutionException(e.getCause()); - } - - @Override - public T get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - return get(); - } - }; - } - return ((Future) getContext().getFuture()); - } - - /** - * one way async call, send request only, and result is not required - * - * @param runnable - */ - public void asyncCall(Runnable runnable) { - try { - setAttachment(Constants.RETURN_KEY, Boolean.FALSE.toString()); - runnable.run(); - } catch (Throwable e) { - // FIXME should put exception in future? - throw new RpcException("oneway call error ." + e.getMessage(), e); - } finally { - removeAttachment(Constants.RETURN_KEY); - } - } - - /** - * @return - * @throws IllegalStateException - */ - @SuppressWarnings("unchecked") - public static AsyncContext startAsync() throws IllegalStateException { - RpcContext currentContext = getContext(); - if (currentContext.asyncContext != null) { - currentContext.asyncContext.start(); - return currentContext.asyncContext; - } else { - throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); - } - } - - public boolean isAsyncStarted() { - if (this.asyncContext == null) { - return false; - } - return asyncContext.isAsyncStarted(); - } - - public boolean stopAsync() { - boolean stoped = asyncContext.stop(); - asyncContext = null; - return stoped; - } - - public void setAsyncContext(AsyncContext asyncContext) { - this.asyncContext = asyncContext; - } - - public AsyncContext getAsyncContext() { - return asyncContext; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java deleted file mode 100644 index 699a7d0a52f..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc; - -/** - * 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 = exception; - } - - @Override - public Object recreate() throws Throwable { - if (exception != null) { - throw exception; - } - return result; - } - - /** - * @see com.alibaba.dubbo.rpc.RpcResult#getValue() - * @deprecated Replace to getValue() - */ - @Override - @Deprecated - public Object getResult() { - return getValue(); - } - - /** - * @see com.alibaba.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 = e; - } - - @Override - public boolean hasException() { - return exception != null; - } - - @Override - public String toString() { - return "RpcResult [result=" + result + ", exception=" + exception + "]"; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java deleted file mode 100644 index 3c1b5e4a38c..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ConsumerContextFilter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.filter; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.utils.NetUtils; -import com.alibaba.dubbo.rpc.Filter; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; - -/** - * ConsumerContextInvokerFilter - */ -@Activate(group = Constants.CONSUMER, order = -10000) -public class ConsumerContextFilter implements Filter { - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - RpcContext.getContext() - .setInvoker(invoker) - .setInvocation(invocation) - .setLocalAddress(NetUtils.getLocalHost(), 0) - .setRemoteAddress(invoker.getUrl().getHost(), - invoker.getUrl().getPort()); - if (invocation instanceof RpcInvocation) { - ((RpcInvocation) invocation).setInvoker(invoker); - } - try { - Result result = invoker.invoke(invocation); - RpcContext.getServerContext().setAttachments(result.getAttachments()); - return result; - } finally { - RpcContext.getContext().clearAttachments(); - } - } - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java deleted file mode 100644 index 82c43905df0..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ContextFilter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.filter; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.rpc.Filter; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; - -import java.util.HashMap; -import java.util.Map; - -/** - * ContextInvokerFilter - */ -@Activate(group = Constants.PROVIDER, order = -10000) -public class ContextFilter implements Filter { - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - Map attachments = invocation.getAttachments(); - if (attachments != null) { - attachments = new HashMap(attachments); - attachments.remove(Constants.PATH_KEY); - attachments.remove(Constants.GROUP_KEY); - attachments.remove(Constants.VERSION_KEY); - attachments.remove(Constants.DUBBO_VERSION_KEY); - attachments.remove(Constants.TOKEN_KEY); - attachments.remove(Constants.TIMEOUT_KEY); - attachments.remove(Constants.ASYNC_KEY);// Remove async property to avoid being passed to the following invoke chain. - } - RpcContext.getContext() - .setInvoker(invoker) - .setInvocation(invocation) -// .setAttachments(attachments) // merged from dubbox - .setLocalAddress(invoker.getUrl().getHost(), - invoker.getUrl().getPort()); - - // mreged from dubbox - // we may already added some attachments into RpcContext before this filter (e.g. in rest protocol) - if (attachments != null) { - if (RpcContext.getContext().getAttachments() != null) { - RpcContext.getContext().getAttachments().putAll(attachments); - } else { - RpcContext.getContext().setAttachments(attachments); - } - } - - if (invocation instanceof RpcInvocation) { - ((RpcInvocation) invocation).setInvoker(invoker); - } - try { - Result result = invoker.invoke(invocation); - // pass attachments to result - result.addAttachments(RpcContext.getServerContext().getAttachments()); - return result; - } finally { - // TODO must we remove the whole context completely? - RpcContext.removeContext(); - RpcContext.getServerContext().clearAttachments(); - } - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java deleted file mode 100644 index 8c7446fe590..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/ExceptionFilter.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.filter; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.rpc.AsyncRpcResult; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.PostProcessFilter; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcResult; -import com.alibaba.dubbo.rpc.service.GenericService; - -import java.lang.reflect.Method; -import java.util.concurrent.CompletableFuture; - -/** - * ExceptionInvokerFilter - *

- * Functions: - *

    - *
  1. unexpected exception will be logged in ERROR level on provider side. Unexpected exception are unchecked - * exception not declared on the interface
  2. - *
  3. Wrap the exception not introduced in API package into RuntimeException. Framework will serialize the outer exception but stringnize its cause in order to avoid of possible serialization problem on client side
  4. - *
- */ -@Activate(group = Constants.PROVIDER) -public class ExceptionFilter implements PostProcessFilter { - - private final Logger logger; - - public ExceptionFilter() { - this(LoggerFactory.getLogger(ExceptionFilter.class)); - } - - public ExceptionFilter(Logger logger) { - this.logger = logger; - } - - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - try { - Result result = invoker.invoke(invocation); - if (result instanceof AsyncRpcResult) { - AsyncRpcResult asyncResult = (AsyncRpcResult) result; - CompletableFuture future = asyncResult.getResultFuture(); - asyncResult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); - return asyncResult; - } else { - return postProcessResult(result, invoker, 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; - } - } - - public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { - if (result.hasException() && GenericService.class != invoker.getInterface()) { - try { - Throwable exception = result.getException(); - - // 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 - 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; - } - } - } 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); - - // 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; - } - - // 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; - } - } - return result; - } - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java deleted file mode 100644 index 1e3ed49fe0f..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.proxy; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.ProxyFactory; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.service.EchoService; -import com.alibaba.dubbo.rpc.service.GenericService; - -/** - * AbstractProxyFactory - */ -public abstract class AbstractProxyFactory implements ProxyFactory { - - @Override - public T getProxy(Invoker invoker) throws RpcException { - return getProxy(invoker, false); - } - - @Override - public T getProxy(Invoker invoker, boolean generic) throws RpcException { - Class[] interfaces = null; - String config = invoker.getUrl().getParameter(Constants.INTERFACES); - if (config != null && config.length() > 0) { - String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); - if (types != null && types.length > 0) { - interfaces = new Class[types.length + 2]; - interfaces[0] = invoker.getInterface(); - interfaces[1] = EchoService.class; - for (int i = 0; i < types.length; i++) { - // TODO can we load successfully for a different classloader?. - interfaces[i + 2] = ReflectUtils.forName(types[i]); - } - } - } - if (interfaces == null) { - interfaces = new Class[]{invoker.getInterface(), EchoService.class}; - } - - if (!invoker.getInterface().equals(GenericService.class) && generic) { - int len = interfaces.length; - Class[] temp = interfaces; - interfaces = new Class[len + 1]; - System.arraycopy(temp, 0, interfaces, 0, len); - interfaces[len] = GenericService.class; - } - - return getProxy(invoker, interfaces); - } - - public abstract T getProxy(Invoker invoker, Class[] types); - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java deleted file mode 100644 index c1cbd3c6988..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.proxy; - -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.AsyncRpcResult; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcResult; -import com.alibaba.dubbo.rpc.support.RpcUtils; - -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.CompletableFuture; - -/** - * InvokerWrapper - */ -public abstract class AbstractProxyInvoker implements Invoker { - - private final T proxy; - - private final Class type; - - private final URL url; - - public AbstractProxyInvoker(T proxy, Class type, URL url) { - if (proxy == null) { - throw new IllegalArgumentException("proxy == null"); - } - if (type == null) { - throw new IllegalArgumentException("interface == null"); - } - if (!type.isInstance(proxy)) { - throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type); - } - this.proxy = proxy; - this.type = type; - this.url = url; - } - - @Override - public Class getInterface() { - return type; - } - - @Override - public URL getUrl() { - return url; - } - - @Override - public boolean isAvailable() { - return true; - } - - @Override - public void destroy() { - } - - // TODO Unified to AsyncResult? - @Override - public Result invoke(Invocation invocation) throws RpcException { - try { - Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); - if (RpcUtils.isFutureReturnType(invocation)) { - return new AsyncRpcResult((CompletableFuture) obj); - } else if (RpcContext.getContext().isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. - return new AsyncRpcResult(RpcContext.getContext().getAsyncContext().getInternalFuture()); - } else { - return new RpcResult(obj); - } - } catch (InvocationTargetException e) { - // TODO async throw exception before async thread write back, should stop asyncContext - return new RpcResult(e.getTargetException()); - } catch (Throwable e) { - throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e); - } - } - - protected abstract Object doInvoke(T proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable; - - @Override - public String toString() { - return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString()); - } - - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java deleted file mode 100644 index 7e7cc4e60bd..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.proxy; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.support.RpcUtils; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; - -/** - * InvokerHandler - */ -public class InvokerInvocationHandler implements InvocationHandler { - - private final Invoker invoker; - - public InvokerInvocationHandler(Invoker handler) { - this.invoker = handler; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String methodName = method.getName(); - Class[] parameterTypes = method.getParameterTypes(); - if (method.getDeclaringClass() == Object.class) { - return method.invoke(invoker, args); - } - if ("toString".equals(methodName) && parameterTypes.length == 0) { - return invoker.toString(); - } - if ("hashCode".equals(methodName) && parameterTypes.length == 0) { - return invoker.hashCode(); - } - if ("equals".equals(methodName) && parameterTypes.length == 1) { - return invoker.equals(args[0]); - } - - RpcInvocation invocation; - if (RpcUtils.hasGeneratedFuture(method)) { - Class clazz = method.getDeclaringClass(); - String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); - Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes()); - invocation = new RpcInvocation(syncMethod, args); - invocation.setAttachment(Constants.FUTURE_GENERATED_KEY, "true"); - invocation.setAttachment(Constants.ASYNC_KEY, "true"); - } else { - invocation = new RpcInvocation(method, args); - if (RpcUtils.hasFutureReturnType(method)) { - invocation.setAttachment(Constants.FUTURE_RETURNTYPE_KEY, "true"); - invocation.setAttachment(Constants.ASYNC_KEY, "true"); - } - } - return invoker.invoke(invocation).recreate(); - } - - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java deleted file mode 100644 index 6930b22f70a..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.support; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.config.AsyncFor; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.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; - -/** - * RpcUtils - */ -public class RpcUtils { - - private static final Logger logger = LoggerFactory.getLogger(RpcUtils.class); - private static final AtomicLong INVOKE_ID = new AtomicLong(0); - - public static Class getReturnType(Invocation invocation) { - try { - if (invocation != null && invocation.getInvoker() != null - && invocation.getInvoker().getUrl() != null - && !invocation.getMethodName().startsWith("$")) { - String service = invocation.getInvoker().getUrl().getServiceInterface(); - if (service != null && service.length() > 0) { - Class cls = ReflectUtils.forName(service); - Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes()); - if (method.getReturnType() == void.class) { - return null; - } - return method.getReturnType(); - } - } - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - return null; - } - - // TODO why not get return type when initialize Invocation? - public static Type[] getReturnTypes(Invocation invocation) { - try { - if (invocation != null && invocation.getInvoker() != null - && invocation.getInvoker().getUrl() != null - && !invocation.getMethodName().startsWith("$")) { - String service = invocation.getInvoker().getUrl().getServiceInterface(); - if (service != null && service.length() > 0) { - Class cls = ReflectUtils.forName(service); - Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes()); - if (method.getReturnType() == void.class) { - return null; - } - Class returnType = method.getReturnType(); - Type genericReturnType = method.getGenericReturnType(); - if (Future.class.isAssignableFrom(returnType)) { - if (genericReturnType instanceof ParameterizedType) { - returnType = (Class) ((ParameterizedType) genericReturnType).getActualTypeArguments()[0]; - } - genericReturnType = returnType; // TODO Can we handle nested generic? for example CompletableFuture> - } else { - genericReturnType = returnType; - } - return new Type[]{returnType, genericReturnType}; - } - } - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - return null; - } - - public static Long getInvocationId(Invocation inv) { - String id = inv.getAttachment(Constants.ID_KEY); - return id == null ? null : new Long(id); - } - - /** - * Idempotent operation: invocation id will be added in async operation by default - * - * @param url - * @param inv - */ - public static void attachInvocationIdIfAsync(URL url, Invocation inv) { - if (isAttachInvocationId(url, inv) && getInvocationId(inv) == null && inv instanceof RpcInvocation) { - ((RpcInvocation) inv).setAttachment(Constants.ID_KEY, String.valueOf(INVOKE_ID.getAndIncrement())); - } - } - - private static boolean isAttachInvocationId(URL url, Invocation invocation) { - String value = url.getMethodParameter(invocation.getMethodName(), Constants.AUTO_ATTACH_INVOCATIONID_KEY); - if (value == null) { - // add invocationid in async operation by default - return isAsync(url, invocation); - } else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) { - return true; - } else { - return false; - } - } - - public static String getMethodName(Invocation invocation) { - if (Constants.$INVOKE.equals(invocation.getMethodName()) - && invocation.getArguments() != null - && invocation.getArguments().length > 0 - && invocation.getArguments()[0] instanceof String) { - return (String) invocation.getArguments()[0]; - } - return invocation.getMethodName(); - } - - public static Object[] getArguments(Invocation invocation) { - if (Constants.$INVOKE.equals(invocation.getMethodName()) - && invocation.getArguments() != null - && invocation.getArguments().length > 2 - && invocation.getArguments()[2] instanceof Object[]) { - return (Object[]) invocation.getArguments()[2]; - } - return invocation.getArguments(); - } - - public static Class[] getParameterTypes(Invocation invocation) { - if (Constants.$INVOKE.equals(invocation.getMethodName()) - && invocation.getArguments() != null - && invocation.getArguments().length > 1 - && invocation.getArguments()[1] instanceof String[]) { - String[] types = (String[]) invocation.getArguments()[1]; - if (types == null) { - return new Class[0]; - } - Class[] parameterTypes = new Class[types.length]; - for (int i = 0; i < types.length; i++) { - parameterTypes[i] = ReflectUtils.forName(types[0]); - } - return parameterTypes; - } - return invocation.getParameterTypes(); - } - - public static boolean isAsync(URL url, Invocation inv) { - boolean isAsync; - if (Boolean.TRUE.toString().equals(inv.getAttachment(Constants.ASYNC_KEY))) { - isAsync = true; - } else { - isAsync = url.getMethodParameter(getMethodName(inv), Constants.ASYNC_KEY, false); - } - return isAsync; - } - - public static boolean isGeneratedFuture(Invocation inv) { - return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_GENERATED_KEY)); - } - - public static boolean hasGeneratedFuture(Method method) { - Class clazz = method.getDeclaringClass(); - return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && hasFutureReturnType(method); - } - - public static boolean isFutureReturnType(Invocation inv) { - return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_RETURNTYPE_KEY)); - } - - public static boolean hasFutureReturnType(Method method) { - return CompletableFuture.class.isAssignableFrom(method.getReturnType()); - } - - public static boolean isOneway(URL url, Invocation inv) { - boolean isOneway; - if (Boolean.FALSE.toString().equals(inv.getAttachment(Constants.RETURN_KEY))) { - isOneway = true; - } else { - isOneway = !url.getMethodParameter(getMethodName(inv), Constants.RETURN_KEY, true); - } - return isOneway; - } - - public static Map getNecessaryAttachments(Invocation inv) { - Map attachments = new HashMap<>(inv.getAttachments()); - attachments.remove(Constants.ASYNC_KEY); - attachments.remove(Constants.FUTURE_GENERATED_KEY); - return attachments; - } - -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractResult.java similarity index 98% rename from dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java rename to dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractResult.java index aa63115cc62..064fd9fd90c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/AbstractResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractResult.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc; +package org.apache.dubbo.rpc; import java.util.HashMap; import java.util.Map; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java index dca53ce46a4..2d8c5ff5c53 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java @@ -16,8 +16,12 @@ */ package org.apache.dubbo.rpc; +import java.util.concurrent.CompletableFuture; + public interface AsyncContext { + CompletableFuture getInternalFuture(); + void addListener(Runnable run); void write(Object value); @@ -27,4 +31,7 @@ public interface AsyncContext { boolean stop(); void start(); + + void signalContextSwitch(); } + diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java index d169587469f..198633db14c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java @@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; - public class AsyncContextImpl implements AsyncContext { private static final Logger logger = LoggerFactory.getLogger(AsyncContextImpl.class); @@ -46,10 +45,9 @@ public void write(Object value) { if (stop()) { if (value instanceof Throwable) { // TODO check exception type like ExceptionFilter do. - Throwable bizExe = (Throwable) value; - future.complete(new RpcResult(bizExe)); + future.completeExceptionally((Throwable) value); } - future.complete(new RpcResult(value)); + future.complete(value); } else { throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); } @@ -73,4 +71,14 @@ public boolean stop() { public void start() { this.started.set(true); } + + @Override + public void signalContextSwitch() { + + } + + @Override + public CompletableFuture getInternalFuture() { + return future; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncResult.java deleted file mode 100644 index bf314a7a7a0..00000000000 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncResult.java +++ /dev/null @@ -1,60 +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.Map; - -/** - * - */ -public abstract class AsyncResult implements Result { - - @Override - public Object getValue() { - return null; - } - - @Override - public Throwable getException() { - return null; - } - - @Override - public boolean hasException() { - return false; - } - - @Override - public Object getResult() { - return null; - } - - @Override - public Map getAttachments() { - return null; - } - - @Override - public String getAttachment(String key) { - return null; - } - - @Override - public String getAttachment(String key, String defaultValue) { - return null; - } -} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java index dfc05985c5f..8cd1f67ba02 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java @@ -16,25 +16,100 @@ */ package org.apache.dubbo.rpc; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; -/** - * - */ -public class AsyncRpcResult extends AsyncResult { - private CompletableFuture future; +public class AsyncRpcResult extends AbstractResult { + private static final Logger logger = LoggerFactory.getLogger(AsyncRpcResult.class); + + private Map attachments = new HashMap(); + + protected CompletableFuture valueFuture; + + protected CompletableFuture resultFuture; + + public AsyncRpcResult(CompletableFuture future) { + this(future, true); + } - public AsyncRpcResult(CompletableFuture future) { - this.future = future; + public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { + if (registerCallback) { + resultFuture = new CompletableFuture<>(); + /** + * 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, is Dubbo thread. + * 2. future complete after whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread calling complete, normally is 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); + } + resultFuture.complete(rpcResult); + }); + } + this.valueFuture = future; } - public CompletableFuture getFuture() { - return future; + @Override + public Object getValue() { + return getRpcResult().getValue(); + } + + @Override + public Throwable getException() { + return getRpcResult().getException(); + } + + @Override + public boolean hasException() { + return getRpcResult().hasException(); + } + + @Override + public Object getResult() { + return getRpcResult().getResult(); + } + + public CompletableFuture getValueFuture() { + return valueFuture; + } + + public CompletableFuture getResultFuture() { + return resultFuture; + } + + public void setResultFuture(CompletableFuture resultFuture) { + this.resultFuture = resultFuture; + } + + public Result getRpcResult() { + Result result; + try { + result = resultFuture.get(); + } catch (Exception e) { + // This should never happen; + logger.error("", e); + result = new RpcResult(); + } + return result; } @Override public Object recreate() throws Throwable { - return future; + return valueFuture; } } + diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java similarity index 97% rename from dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java rename to dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java index e6475277f69..e0a0c2dbe44 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/PostProcessFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc; +package org.apache.dubbo.rpc; /** * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java index 90b772fb0de..e2b652116d4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java @@ -16,8 +16,10 @@ */ package org.apache.dubbo.rpc; +import java.io.Serializable; import java.util.Map; + /** * RPC invoke result. (API, Prototype, NonThreadSafe) * @@ -25,7 +27,7 @@ * @see org.apache.dubbo.rpc.Invoker#invoke(Invocation) * @see org.apache.dubbo.rpc.RpcResult */ -public interface Result { +public interface Result extends Serializable { /** * Get invoke result. @@ -79,6 +81,20 @@ public interface Result { */ Map getAttachments(); + /** + * Add the specified map to existing attachments in this instance. + * + * @param map + */ + public void addAttachments(Map map); + + /** + * Replace the existing attachments with the specified param. + * + * @param map + */ + public void setAttachments(Map map); + /** * get attachment by key. * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index 068dc9f50c1..efef6885776 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + /** * Thread local context. (API, ThreadLocal, ThreadSafe) *

@@ -43,7 +44,7 @@ * starts invoking C, and saves invocation info from B to C after B invokes C. * * @export - * @see org.apache.dubbo.rpc.filter.ContextFilter + * @see com.alibaba.dubbo.rpc.filter.ContextFilter */ public class RpcContext { @@ -108,7 +109,7 @@ public static RpcContext getServerContext() { /** * remove server side context. * - * @see org.apache.dubbo.rpc.filter.ContextFilter + * @see com.alibaba.dubbo.rpc.filter.ContextFilter */ public static void removeServerContext() { SERVER_LOCAL.remove(); @@ -126,29 +127,12 @@ public static RpcContext getContext() { /** * remove context. * - * @see org.apache.dubbo.rpc.filter.ContextFilter + * @see com.alibaba.dubbo.rpc.filter.ContextFilter */ public static void removeContext() { LOCAL.remove(); } - /** - * TODO call multiple times in different thread? - * - * @return - * @throws IllegalStateException - */ - @SuppressWarnings("unchecked") - public static AsyncContext startAsync() throws IllegalStateException { - RpcContext currentContext = getContext(); - if (currentContext.asyncContext != null) { - currentContext.asyncContext.start(); - return currentContext.asyncContext; - } else { - throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); - } - } - /** * Get the request object of the underlying RPC protocol, e.g. HttpServletRequest * @@ -709,6 +693,21 @@ public void asyncCall(Runnable runnable) { } } + /** + * @return + * @throws IllegalStateException + */ + @SuppressWarnings("unchecked") + public static AsyncContext startAsync() throws IllegalStateException { + RpcContext currentContext = getContext(); + if (currentContext.asyncContext != null) { + currentContext.asyncContext.start(); + return currentContext.asyncContext; + } else { + throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); + } + } + public boolean isAsyncStarted() { if (this.asyncContext == null) { return false; @@ -725,4 +724,8 @@ public boolean stopAsync() { public void setAsyncContext(AsyncContext asyncContext) { this.asyncContext = asyncContext; } + + public AsyncContext getAsyncContext() { + return asyncContext; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java index 17fbbf0a632..cca7b365f31 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java @@ -16,25 +16,15 @@ */ package org.apache.dubbo.rpc; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - /** * RPC Result. * * @serial Don't change the class name and properties. */ -public class RpcResult implements Result, Serializable { +public class RpcResult extends AbstractResult { private static final long serialVersionUID = -6925924956850004727L; - private Object result; - - private Throwable exception; - - private Map attachments = new HashMap(); - public RpcResult() { } @@ -55,7 +45,7 @@ public Object recreate() throws Throwable { } /** - * @see org.apache.dubbo.rpc.RpcResult#getValue() + * @see com.alibaba.dubbo.rpc.RpcResult#getValue() * @deprecated Replace to getValue() */ @Override @@ -65,7 +55,7 @@ public Object getResult() { } /** - * @see org.apache.dubbo.rpc.RpcResult#setValue(Object) + * @see com.alibaba.dubbo.rpc.RpcResult#setValue(Object) * @deprecated Replace to setValue() */ @Deprecated @@ -96,48 +86,6 @@ public boolean hasException() { return exception != null; } - @Override - public Map 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 map) { - this.attachments = map == null ? new HashMap() : map; - } - - public void addAttachments(Map map) { - if (map == null) { - return; - } - if (this.attachments == null) { - this.attachments = new HashMap(); - } - 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 String toString() { return "RpcResult [result=" + result + ", exception=" + exception + "]"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java index 9d4e4e9f2cc..daba2f5f6d4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @@ -26,7 +26,6 @@ import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; -import org.apache.dubbo.rpc.RpcResult; /** * ConsumerContextInvokerFilter @@ -46,7 +45,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - RpcResult result = (RpcResult) invoker.invoke(invocation); + Result result = invoker.invoke(invocation); RpcContext.getServerContext().setAttachments(result.getAttachments()); return result; } finally { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java index 1c74592c040..a38fbb06793 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java @@ -25,7 +25,6 @@ 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 java.util.HashMap; import java.util.Map; @@ -70,7 +69,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - RpcResult result = (RpcResult) invoker.invoke(invocation); + Result result = invoker.invoke(invocation); // pass attachments to result result.addAttachments(RpcContext.getServerContext().getAttachments()); return result; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java index 6d97b93f612..eb36be28a02 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java @@ -22,9 +22,10 @@ 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.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.PostProcessFilter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; @@ -32,6 +33,8 @@ import org.apache.dubbo.rpc.service.GenericService; import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + /** * ExceptionInvokerFilter @@ -44,7 +47,7 @@ * */ @Activate(group = Constants.PROVIDER) -public class ExceptionFilter implements Filter { +public class ExceptionFilter implements PostProcessFilter { private final Logger logger; @@ -60,64 +63,76 @@ public ExceptionFilter(Logger logger) { public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { try { Result result = invoker.invoke(invocation); - if (result.hasException() && GenericService.class != invoker.getInterface()) { - try { - Throwable exception = result.getException(); + if (result instanceof AsyncRpcResult) { + AsyncRpcResult asyncResult = (AsyncRpcResult) result; + CompletableFuture future = asyncResult.getResultFuture(); + asyncResult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); + return asyncResult; + } else { + return postProcessResult(result, invoker, 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; + } + } - // 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 - 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; - } + public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { + if (result.hasException() && GenericService.class != invoker.getInterface()) { + try { + Throwable exception = result.getException(); + + // 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 + 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; } - } catch (NoSuchMethodException e) { - return result; } + } 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); - - // 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; - } + // 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); - // 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); + // 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; } + + // 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; } - return result; - } 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 result; } } + diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java index 8675f348e1b..ae2ac71651f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -17,13 +17,17 @@ package org.apache.dubbo.rpc.proxy; import org.apache.dubbo.common.URL; +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.RpcResult; +import org.apache.dubbo.rpc.support.RpcUtils; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CompletableFuture; /** * InvokerWrapper @@ -70,11 +74,20 @@ public boolean isAvailable() { public void destroy() { } + // TODO Unified to AsyncResult? @Override public Result invoke(Invocation invocation) throws RpcException { try { - return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments())); + Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); + if (RpcUtils.isFutureReturnType(invocation)) { + return new AsyncRpcResult((CompletableFuture) obj); + } else if (RpcContext.getContext().isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. + return new AsyncRpcResult(RpcContext.getContext().getAsyncContext().getInternalFuture()); + } else { + return new RpcResult(obj); + } } catch (InvocationTargetException e) { + // TODO async throw exception before async thread write back, should stop asyncContext return new RpcResult(e.getTargetException()); } catch (Throwable e) { throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java index f5b1c242f96..728b3b9facf 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/InvokerInvocationHandler.java @@ -53,15 +53,19 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl } RpcInvocation invocation; - if (RpcUtils.isAsyncFuture(method)) { + if (RpcUtils.hasGeneratedFuture(method)) { Class clazz = method.getDeclaringClass(); String syncMethodName = methodName.substring(0, methodName.length() - Constants.ASYNC_SUFFIX.length()); Method syncMethod = clazz.getMethod(syncMethodName, method.getParameterTypes()); invocation = new RpcInvocation(syncMethod, args); - invocation.setAttachment(Constants.FUTURE_KEY, "true"); + invocation.setAttachment(Constants.FUTURE_GENERATED_KEY, "true"); invocation.setAttachment(Constants.ASYNC_KEY, "true"); } else { invocation = new RpcInvocation(method, args); + if (RpcUtils.hasFutureReturnType(method)) { + invocation.setAttachment(Constants.FUTURE_RETURNTYPE_KEY, "true"); + invocation.setAttachment(Constants.ASYNC_KEY, "true"); + } } return invoker.invoke(invocation).recreate(); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java index 78b4ed29124..f543181350e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java @@ -26,8 +26,12 @@ 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; /** @@ -59,6 +63,7 @@ public static Class getReturnType(Invocation invocation) { return null; } + // TODO why not get return type when initialize Invocation? public static Type[] getReturnTypes(Invocation invocation) { try { if (invocation != null && invocation.getInvoker() != null @@ -71,7 +76,17 @@ public static Type[] getReturnTypes(Invocation invocation) { if (method.getReturnType() == void.class) { return null; } - return new Type[]{method.getReturnType(), method.getGenericReturnType()}; + Class returnType = method.getReturnType(); + Type genericReturnType = method.getGenericReturnType(); + if (Future.class.isAssignableFrom(returnType)) { + if (genericReturnType instanceof ParameterizedType) { + returnType = (Class) ((ParameterizedType) genericReturnType).getActualTypeArguments()[0]; + } + genericReturnType = returnType; // TODO Can we handle nested generic? for example CompletableFuture> + } else { + genericReturnType = returnType; + } + return new Type[]{returnType, genericReturnType}; } } } catch (Throwable t) { @@ -157,13 +172,21 @@ public static boolean isAsync(URL url, Invocation inv) { return isAsync; } - public static boolean isAsyncFuture(URL url, Invocation inv) { - return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_KEY)); + public static boolean isGeneratedFuture(Invocation inv) { + return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_GENERATED_KEY)); } - public static boolean isAsyncFuture(Method method) { + public static boolean hasGeneratedFuture(Method method) { Class clazz = method.getDeclaringClass(); - return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && method.getReturnType().equals(CompletableFuture.class); + return clazz.isAnnotationPresent(AsyncFor.class) && method.getName().endsWith(Constants.ASYNC_SUFFIX) && hasFutureReturnType(method); + } + + public static boolean isFutureReturnType(Invocation inv) { + return Boolean.TRUE.toString().equals(inv.getAttachment(Constants.FUTURE_RETURNTYPE_KEY)); + } + + public static boolean hasFutureReturnType(Method method) { + return CompletableFuture.class.isAssignableFrom(method.getReturnType()); } public static boolean isOneway(URL url, Invocation inv) { @@ -176,4 +199,11 @@ public static boolean isOneway(URL url, Invocation inv) { return isOneway; } + public static Map getNecessaryAttachments(Invocation inv) { + Map attachments = new HashMap<>(inv.getAttachments()); + attachments.remove(Constants.ASYNC_KEY); + attachments.remove(Constants.FUTURE_GENERATED_KEY); + return attachments; + } + } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java deleted file mode 100644 index 1dba7905cac..00000000000 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.protocol.dubbo; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.Version; -import com.alibaba.dubbo.common.io.Bytes; -import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.serialize.ObjectInput; -import com.alibaba.dubbo.common.serialize.ObjectOutput; -import com.alibaba.dubbo.common.serialize.Serialization; -import com.alibaba.dubbo.common.utils.ReflectUtils; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.Codec2; -import com.alibaba.dubbo.remoting.exchange.Request; -import com.alibaba.dubbo.remoting.exchange.Response; -import com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec; -import com.alibaba.dubbo.remoting.transport.CodecSupport; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.support.RpcUtils; - -import java.io.IOException; -import java.io.InputStream; - -import static com.alibaba.dubbo.rpc.protocol.dubbo.CallbackServiceCodec.encodeInvocationArgument; - -/** - * Dubbo codec. - */ -public class DubboCodec extends ExchangeCodec implements Codec2 { - - public static final String NAME = "dubbo"; - public static final String DUBBO_VERSION = Version.getProtocolVersion(); - public static final byte RESPONSE_WITH_EXCEPTION = 0; - public static final byte RESPONSE_VALUE = 1; - public static final byte RESPONSE_NULL_VALUE = 2; - public static final byte RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS = 3; - public static final byte RESPONSE_VALUE_WITH_ATTACHMENTS = 4; - public static final byte RESPONSE_NULL_VALUE_WITH_ATTACHMENTS = 5; - public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - private static final Logger log = LoggerFactory.getLogger(DubboCodec.class); - - @Override - protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException { - byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK); - Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto); - // get request id. - long id = Bytes.bytes2long(header, 4); - if ((flag & FLAG_REQUEST) == 0) { - // decode response. - Response res = new Response(id); - if ((flag & FLAG_EVENT) != 0) { - res.setEvent(Response.HEARTBEAT_EVENT); - } - // get status. - byte status = header[3]; - res.setStatus(status); - if (status == Response.OK) { - try { - Object data; - if (res.isHeartbeat()) { - data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(), is)); - } else if (res.isEvent()) { - data = decodeEventData(channel, deserialize(s, channel.getUrl(), is)); - } else { - DecodeableRpcResult result; - if (channel.getUrl().getParameter( - Constants.DECODE_IN_IO_THREAD_KEY, - Constants.DEFAULT_DECODE_IN_IO_THREAD)) { - result = new DecodeableRpcResult(channel, res, is, - (Invocation) getRequestData(id), proto); - result.decode(); - } else { - result = new DecodeableRpcResult(channel, res, - new UnsafeByteArrayInputStream(readMessageData(is)), - (Invocation) getRequestData(id), proto); - } - data = result; - } - res.setResult(data); - } catch (Throwable t) { - if (log.isWarnEnabled()) { - log.warn("Decode response failed: " + t.getMessage(), t); - } - res.setStatus(Response.CLIENT_ERROR); - res.setErrorMessage(StringUtils.toString(t)); - } - } else { - res.setErrorMessage(deserialize(s, channel.getUrl(), is).readUTF()); - } - return res; - } else { - // decode request. - Request req = new Request(id); - req.setVersion(Version.getProtocolVersion()); - req.setTwoWay((flag & FLAG_TWOWAY) != 0); - if ((flag & FLAG_EVENT) != 0) { - req.setEvent(Request.HEARTBEAT_EVENT); - } - try { - Object data; - if (req.isHeartbeat()) { - data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(), is)); - } else if (req.isEvent()) { - data = decodeEventData(channel, deserialize(s, channel.getUrl(), is)); - } else { - DecodeableRpcInvocation inv; - if (channel.getUrl().getParameter( - Constants.DECODE_IN_IO_THREAD_KEY, - Constants.DEFAULT_DECODE_IN_IO_THREAD)) { - inv = new DecodeableRpcInvocation(channel, req, is, proto); - inv.decode(); - } else { - inv = new DecodeableRpcInvocation(channel, req, - new UnsafeByteArrayInputStream(readMessageData(is)), proto); - } - data = inv; - } - req.setData(data); - } catch (Throwable t) { - if (log.isWarnEnabled()) { - log.warn("Decode request failed: " + t.getMessage(), t); - } - // bad request - req.setBroken(true); - req.setData(t); - } - return req; - } - } - - private ObjectInput deserialize(Serialization serialization, URL url, InputStream is) - throws IOException { - return serialization.deserialize(url, is); - } - - private byte[] readMessageData(InputStream is) throws IOException { - if (is.available() > 0) { - byte[] result = new byte[is.available()]; - is.read(result); - return result; - } - return new byte[]{}; - } - - @Override - protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { - encodeRequestData(channel, out, data, DUBBO_VERSION); - } - - @Override - protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException { - encodeResponseData(channel, out, data, DUBBO_VERSION); - } - - @Override - protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException { - RpcInvocation inv = (RpcInvocation) data; - - out.writeUTF(version); - out.writeUTF(inv.getAttachment(Constants.PATH_KEY)); - out.writeUTF(inv.getAttachment(Constants.VERSION_KEY)); - - out.writeUTF(inv.getMethodName()); - out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes())); - Object[] args = inv.getArguments(); - if (args != null) - for (int i = 0; i < args.length; i++) { - out.writeObject(encodeInvocationArgument(channel, inv, i)); - } - out.writeObject(RpcUtils.getNecessaryAttachments(inv)); - } - - @Override - protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException { - Result result = (Result) data; - // currently, the version value in Response records the version of Request - boolean attach = Version.isSupportResponseAttatchment(version); - Throwable th = result.getException(); - if (th == null) { - Object ret = result.getValue(); - if (ret == null) { - out.writeByte(attach ? RESPONSE_NULL_VALUE_WITH_ATTACHMENTS : RESPONSE_NULL_VALUE); - } else { - out.writeByte(attach ? RESPONSE_VALUE_WITH_ATTACHMENTS : RESPONSE_VALUE); - out.writeObject(ret); - } - } else { - out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION); - out.writeObject(th); - } - - if (attach) { - // returns current version of Response to consumer side. - result.getAttachments().put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()); - out.writeObject(result.getAttachments()); - } - } -} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java deleted file mode 100644 index 2ac8347bc48..00000000000 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.protocol.dubbo; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.utils.AtomicPositiveInteger; -import com.alibaba.dubbo.common.utils.ConfigUtils; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.TimeoutException; -import com.alibaba.dubbo.remoting.exchange.ExchangeClient; -import com.alibaba.dubbo.remoting.exchange.ResponseFuture; -import com.alibaba.dubbo.rpc.AsyncRpcResult; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.RpcResult; -import com.alibaba.dubbo.rpc.protocol.AbstractInvoker; -import com.alibaba.dubbo.rpc.support.RpcUtils; - -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; - -/** - * DubboInvoker - */ -public class DubboInvoker extends AbstractInvoker { - - private final ExchangeClient[] clients; - - private final AtomicPositiveInteger index = new AtomicPositiveInteger(); - - private final String version; - - private final ReentrantLock destroyLock = new ReentrantLock(); - - private final Set> invokers; - - public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients) { - this(serviceType, url, clients, null); - } - - public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients, Set> invokers) { - super(serviceType, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY}); - this.clients = clients; - // get version. - this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0"); - this.invokers = invokers; - } - - @Override - protected Result doInvoke(final Invocation invocation) throws Throwable { - RpcInvocation inv = (RpcInvocation) invocation; - final String methodName = RpcUtils.getMethodName(invocation); - inv.setAttachment(Constants.PATH_KEY, getUrl().getPath()); - inv.setAttachment(Constants.VERSION_KEY, version); - - ExchangeClient currentClient; - if (clients.length == 1) { - currentClient = clients[0]; - } else { - currentClient = clients[index.getAndIncrement() % clients.length]; - } - try { - boolean isAsync = RpcUtils.isAsync(getUrl(), invocation); - boolean isAsyncFuture = RpcUtils.isGeneratedFuture(inv) || RpcUtils.isFutureReturnType(inv); - boolean isOneway = RpcUtils.isOneway(getUrl(), invocation); - int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); - if (isOneway) { - boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false); - currentClient.send(inv, isSent); - RpcContext.getContext().setFuture(null); - return new RpcResult(); - } else if (isAsync) { - ResponseFuture future = currentClient.request(inv, timeout); - FutureAdapter futureAdapter = new FutureAdapter<>(future); - RpcContext.getContext().setFuture(futureAdapter); - Result result; - if (isAsyncFuture) { - // register resultCallback, sometimes we need the result being processed in the filter chain. - result = new AsyncRpcResult(futureAdapter, true); - } else { - result = new RpcResult(); - } - return result; - } else { - RpcContext.getContext().setFuture(null); - return (Result) currentClient.request(inv, timeout).get(); - } - } catch (TimeoutException e) { - throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); - } catch (RemotingException e) { - throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); - } - } - - @Override - public boolean isAvailable() { - if (!super.isAvailable()) - return false; - for (ExchangeClient client : clients) { - if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)) { - //cannot write == not Available ? - return true; - } - } - return false; - } - - @Override - public void destroy() { - // in order to avoid closing a client multiple times, a counter is used in case of connection per jvm, every - // time when client.close() is called, counter counts down once, and when counter reaches zero, client will be - // closed. - if (super.isDestroyed()) { - return; - } else { - // double check to avoid dup close - destroyLock.lock(); - try { - if (super.isDestroyed()) { - return; - } - super.destroy(); - if (invokers != null) { - invokers.remove(this); - } - for (ExchangeClient client : clients) { - try { - client.close(ConfigUtils.getServerShutdownTimeout()); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - - } finally { - destroyLock.unlock(); - } - } - } -} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java deleted file mode 100644 index ae362741e14..00000000000 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.protocol.dubbo; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.extension.ExtensionLoader; -import com.alibaba.dubbo.common.serialize.support.SerializableClassRegistry; -import com.alibaba.dubbo.common.serialize.support.SerializationOptimizer; -import com.alibaba.dubbo.common.utils.ConcurrentHashSet; -import com.alibaba.dubbo.common.utils.ConfigUtils; -import com.alibaba.dubbo.common.utils.NetUtils; -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.Transporter; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeClient; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.ExchangeServer; -import com.alibaba.dubbo.remoting.exchange.Exchangers; -import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import com.alibaba.dubbo.rpc.AsyncContextImpl; -import com.alibaba.dubbo.rpc.AsyncRpcResult; -import com.alibaba.dubbo.rpc.Exporter; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.Protocol; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.protocol.AbstractProtocol; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * dubbo protocol support. - */ -public class DubboProtocol extends AbstractProtocol { - - public static final String NAME = "dubbo"; - - public static final int DEFAULT_PORT = 20880; - private static final String IS_CALLBACK_SERVICE_INVOKE = "_isCallBackServiceInvoke"; - private static DubboProtocol INSTANCE; - private final Map serverMap = new ConcurrentHashMap(); // - private final Map referenceClientMap = new ConcurrentHashMap(); // - private final ConcurrentMap ghostClientMap = new ConcurrentHashMap(); - private final ConcurrentMap locks = new ConcurrentHashMap(); - private final Set optimizers = new ConcurrentHashSet(); - //consumer side export a stub service for dispatching event - //servicekey-stubmethods - private final ConcurrentMap stubServiceMethodsMap = new ConcurrentHashMap(); - private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { - - @Override - public CompletableFuture reply(ExchangeChannel channel, Object message) throws RemotingException { - if (message instanceof Invocation) { - Invocation inv = (Invocation) message; - Invoker invoker = getInvoker(channel, inv); - // need to consider backward-compatibility if it's a callback - if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) { - String methodsStr = invoker.getUrl().getParameters().get("methods"); - boolean hasMethod = false; - if (methodsStr == null || !methodsStr.contains(",")) { - hasMethod = inv.getMethodName().equals(methodsStr); - } else { - String[] methods = methodsStr.split(","); - for (String method : methods) { - if (inv.getMethodName().equals(method)) { - hasMethod = true; - break; - } - } - } - if (!hasMethod) { - logger.warn(new IllegalStateException("The methodName " + inv.getMethodName() - + " not found in callback service interface ,invoke will be ignored." - + " please update the api interface. url is:" - + invoker.getUrl()) + " ,invocation is :" + inv); - return null; - } - } - RpcContext rpcContext = RpcContext.getContext(); - boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); - if (supportServerAsync) { - CompletableFuture future = new CompletableFuture<>(); - rpcContext.setAsyncContext(new AsyncContextImpl(future)); - } - rpcContext.setRemoteAddress(channel.getRemoteAddress()); - Result result = invoker.invoke(inv); - - if (result instanceof AsyncRpcResult) { - return ((AsyncRpcResult) result).getResultFuture().thenApply(r -> (Object) r); - } else { - return CompletableFuture.completedFuture(result); - } - } - throw new RemotingException(channel, "Unsupported request: " - + (message == null ? null : (message.getClass().getName() + ": " + message)) - + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress()); - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - if (message instanceof Invocation) { - reply((ExchangeChannel) channel, message); - } else { - super.received(channel, message); - } - } - - @Override - public void connected(Channel channel) throws RemotingException { - invoke(channel, Constants.ON_CONNECT_KEY); - } - - @Override - public void disconnected(Channel channel) throws RemotingException { - if (logger.isInfoEnabled()) { - logger.info("disconnected from " + channel.getRemoteAddress() + ",url:" + channel.getUrl()); - } - invoke(channel, Constants.ON_DISCONNECT_KEY); - } - - private void invoke(Channel channel, String methodKey) { - Invocation invocation = createInvocation(channel, channel.getUrl(), methodKey); - if (invocation != null) { - try { - received(channel, invocation); - } catch (Throwable t) { - logger.warn("Failed to invoke event method " + invocation.getMethodName() + "(), cause: " + t.getMessage(), t); - } - } - } - - private Invocation createInvocation(Channel channel, URL url, String methodKey) { - String method = url.getParameter(methodKey); - if (method == null || method.length() == 0) { - return null; - } - RpcInvocation invocation = new RpcInvocation(method, new Class[0], new Object[0]); - invocation.setAttachment(Constants.PATH_KEY, url.getPath()); - invocation.setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY)); - invocation.setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY)); - invocation.setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY)); - if (url.getParameter(Constants.STUB_EVENT_KEY, false)) { - invocation.setAttachment(Constants.STUB_EVENT_KEY, Boolean.TRUE.toString()); - } - return invocation; - } - }; - - public DubboProtocol() { - INSTANCE = this; - } - - public static DubboProtocol getDubboProtocol() { - if (INSTANCE == null) { - ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(DubboProtocol.NAME); // load - } - return INSTANCE; - } - - public Collection getServers() { - return Collections.unmodifiableCollection(serverMap.values()); - } - - public Collection> getExporters() { - return Collections.unmodifiableCollection(exporterMap.values()); - } - - Map> getExporterMap() { - return exporterMap; - } - - private boolean isClientSide(Channel channel) { - InetSocketAddress address = channel.getRemoteAddress(); - URL url = channel.getUrl(); - return url.getPort() == address.getPort() && - NetUtils.filterLocalHost(channel.getUrl().getIp()) - .equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress())); - } - - Invoker getInvoker(Channel channel, Invocation inv) throws RemotingException { - boolean isCallBackServiceInvoke = false; - boolean isStubServiceInvoke = false; - int port = channel.getLocalAddress().getPort(); - String path = inv.getAttachments().get(Constants.PATH_KEY); - // if it's callback service on client side - isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(Constants.STUB_EVENT_KEY)); - if (isStubServiceInvoke) { - port = channel.getRemoteAddress().getPort(); - } - //callback - isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke; - if (isCallBackServiceInvoke) { - path = inv.getAttachments().get(Constants.PATH_KEY) + "." + inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY); - inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString()); - } - String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY)); - - DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey); - - if (exporter == null) - throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv); - - return exporter.getInvoker(); - } - - public Collection> getInvokers() { - return Collections.unmodifiableCollection(invokers); - } - - @Override - public int getDefaultPort() { - return DEFAULT_PORT; - } - - @Override - public Exporter export(Invoker invoker) throws RpcException { - URL url = invoker.getUrl(); - - // export service. - String key = serviceKey(url); - DubboExporter exporter = new DubboExporter(invoker, key, exporterMap); - exporterMap.put(key, exporter); - - //export an stub service for dispatching event - Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT); - Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false); - if (isStubSupportEvent && !isCallbackservice) { - String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY); - if (stubServiceMethods == null || stubServiceMethods.length() == 0) { - if (logger.isWarnEnabled()) { - logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) + - "], has set stubproxy support event ,but no stub methods founded.")); - } - } else { - stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); - } - } - - openServer(url); - optimizeSerialization(url); - return exporter; - } - - private void openServer(URL url) { - // find server. - String key = url.getAddress(); - //client can export a service which's only for server to invoke - boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true); - if (isServer) { - ExchangeServer server = serverMap.get(key); - if (server == null) { - synchronized (this) { - server = serverMap.get(key); - if (server == null) { - serverMap.put(key, createServer(url)); - } - } - } else { - // server supports reset, use together with override - server.reset(url); - } - } - } - - private ExchangeServer createServer(URL url) { - // send readonly event when server closes, it's enabled by default - url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()); - // enable heartbeat by default - url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); - String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); - - if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) - throw new RpcException("Unsupported server type: " + str + ", url: " + url); - - url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); - ExchangeServer server; - try { - server = Exchangers.bind(url, requestHandler); - } catch (RemotingException e) { - throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e); - } - str = url.getParameter(Constants.CLIENT_KEY); - if (str != null && str.length() > 0) { - Set supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(); - if (!supportedTypes.contains(str)) { - throw new RpcException("Unsupported client type: " + str); - } - } - return server; - } - - private void optimizeSerialization(URL url) throws RpcException { - String className = url.getParameter(Constants.OPTIMIZER_KEY, ""); - if (StringUtils.isEmpty(className) || optimizers.contains(className)) { - return; - } - - logger.info("Optimizing the serialization process for Kryo, FST, etc..."); - - try { - Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className); - if (!SerializationOptimizer.class.isAssignableFrom(clazz)) { - throw new RpcException("The serialization optimizer " + className + " isn't an instance of " + SerializationOptimizer.class.getName()); - } - - SerializationOptimizer optimizer = (SerializationOptimizer) clazz.newInstance(); - - if (optimizer.getSerializableClasses() == null) { - return; - } - - for (Class c : optimizer.getSerializableClasses()) { - SerializableClassRegistry.registerClass(c); - } - - optimizers.add(className); - } catch (ClassNotFoundException e) { - throw new RpcException("Cannot find the serialization optimizer class: " + className, e); - } catch (InstantiationException e) { - throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e); - } catch (IllegalAccessException e) { - throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e); - } - } - - @Override - public Invoker refer(Class serviceType, URL url) throws RpcException { - optimizeSerialization(url); - // create rpc invoker. - DubboInvoker invoker = new DubboInvoker(serviceType, url, getClients(url), invokers); - invokers.add(invoker); - return invoker; - } - - private ExchangeClient[] getClients(URL url) { - // whether to share connection - boolean service_share_connect = false; - int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0); - // if not configured, connection is shared, otherwise, one connection for one service - if (connections == 0) { - service_share_connect = true; - connections = 1; - } - - ExchangeClient[] clients = new ExchangeClient[connections]; - for (int i = 0; i < clients.length; i++) { - if (service_share_connect) { - clients[i] = getSharedClient(url); - } else { - clients[i] = initClient(url); - } - } - return clients; - } - - /** - * Get shared connection - */ - private ExchangeClient getSharedClient(URL url) { - String key = url.getAddress(); - ReferenceCountExchangeClient client = referenceClientMap.get(key); - if (client != null) { - if (!client.isClosed()) { - client.incrementAndGetCount(); - return client; - } else { - referenceClientMap.remove(key); - } - } - - locks.putIfAbsent(key, new Object()); - synchronized (locks.get(key)) { - if (referenceClientMap.containsKey(key)) { - return referenceClientMap.get(key); - } - - ExchangeClient exchangeClient = initClient(url); - client = new ReferenceCountExchangeClient(exchangeClient, ghostClientMap); - referenceClientMap.put(key, client); - ghostClientMap.remove(key); - locks.remove(key); - return client; - } - } - - /** - * Create new connection - */ - private ExchangeClient initClient(URL url) { - - // client type setting. - String str = url.getParameter(Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_CLIENT)); - - url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); - // enable heartbeat by default - url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); - - // BIO is not allowed since it has severe performance issue. - if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) { - throw new RpcException("Unsupported client type: " + str + "," + - " supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " ")); - } - - ExchangeClient client; - try { - // connection should be lazy - if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)) { - client = new LazyConnectExchangeClient(url, requestHandler); - } else { - client = Exchangers.connect(url, requestHandler); - } - } catch (RemotingException e) { - throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e); - } - return client; - } - - @Override - public void destroy() { - for (String key : new ArrayList(serverMap.keySet())) { - ExchangeServer server = serverMap.remove(key); - if (server != null) { - try { - if (logger.isInfoEnabled()) { - logger.info("Close dubbo server: " + server.getLocalAddress()); - } - server.close(ConfigUtils.getServerShutdownTimeout()); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - } - - for (String key : new ArrayList(referenceClientMap.keySet())) { - ExchangeClient client = referenceClientMap.remove(key); - if (client != null) { - try { - if (logger.isInfoEnabled()) { - logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress()); - } - client.close(ConfigUtils.getServerShutdownTimeout()); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - } - - for (String key : new ArrayList(ghostClientMap.keySet())) { - ExchangeClient client = ghostClientMap.remove(key); - if (client != null) { - try { - if (logger.isInfoEnabled()) { - logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress()); - } - client.close(ConfigUtils.getServerShutdownTimeout()); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } - } - stubServiceMethodsMap.clear(); - super.destroy(); - } -} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java deleted file mode 100644 index 9fc478e9d1c..00000000000 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.protocol.dubbo; - -import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.exchange.ResponseCallback; -import com.alibaba.dubbo.remoting.exchange.ResponseFuture; -import com.alibaba.dubbo.rpc.Result; -import com.alibaba.dubbo.rpc.RpcException; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * FutureAdapter - */ -public class FutureAdapter extends CompletableFuture { - - private final ResponseFuture future; - - public FutureAdapter(ResponseFuture future) { - this.future = future; - future.setCallback(new ResponseCallback() { - @Override - public void done(Object response) { - Result result = (Result) response; - V value = null; - try { - value = (V) result.recreate(); - } catch (Throwable t) { - FutureAdapter.this.completeExceptionally(t); - } - FutureAdapter.this.complete(value); - } - - @Override - public void caught(Throwable exception) { - FutureAdapter.this.completeExceptionally(exception); - } - }); - } - - public ResponseFuture getFuture() { - return future; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return future.isDone(); - } - - @Override - @SuppressWarnings("unchecked") - public V get() throws InterruptedException, ExecutionException { - try { - return (V) (((Result) future.get()).recreate()); - } catch (RemotingException e) { - throw new ExecutionException(e.getMessage(), e); - } catch (Throwable e) { - throw new RpcException(e); - } - } - - @Override - @SuppressWarnings("unchecked") - public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - int timeoutInMillis = (int) TimeUnit.MILLISECONDS.convert(timeout, unit); - try { - return (V) (((Result) future.get(timeoutInMillis)).recreate()); - } catch (com.alibaba.dubbo.remoting.TimeoutException e) { - throw new TimeoutException(StringUtils.toString(e)); - } catch (RemotingException e) { - throw new ExecutionException(e.getMessage(), e); - } catch (Throwable e) { - throw new RpcException(e); - } - } - - -} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboCodec.java index 78970398c3f..7523392c1e7 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboCodec.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboCodec.java @@ -37,6 +37,7 @@ import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.support.RpcUtils; import java.io.IOException; import java.io.InputStream; @@ -188,7 +189,7 @@ protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, for (int i = 0; i < args.length; i++) { out.writeObject(encodeInvocationArgument(channel, inv, i)); } - out.writeObject(inv.getAttachments()); + out.writeObject(RpcUtils.getNecessaryAttachments(inv)); } @Override diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 5b5ed0b3a37..5e4c406e4ca 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -80,6 +80,7 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { } try { boolean isAsync = RpcUtils.isAsync(getUrl(), invocation); + boolean isAsyncFuture = RpcUtils.isGeneratedFuture(inv) || RpcUtils.isFutureReturnType(inv); boolean isOneway = RpcUtils.isOneway(getUrl(), invocation); int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); if (isOneway) { @@ -89,11 +90,12 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { return new RpcResult(); } else if (isAsync) { ResponseFuture future = currentClient.request(inv, timeout); - FutureAdapter futureAdapter = new FutureAdapter<>(future); + FutureAdapter futureAdapter = new FutureAdapter<>(future); RpcContext.getContext().setFuture(futureAdapter); Result result; - if (RpcUtils.isAsyncFuture(getUrl(), inv)) { - result = new AsyncRpcResult<>(futureAdapter); + if (isAsyncFuture) { + // register resultCallback, sometimes we need the result being processed in the filter chain. + result = new AsyncRpcResult(futureAdapter, true); } else { result = new RpcResult(); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 956a2e956f9..d7fe35d3b9c 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -35,6 +35,7 @@ import org.apache.dubbo.remoting.exchange.Exchangers; import org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; import org.apache.dubbo.rpc.AsyncContextImpl; +import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -103,23 +104,20 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) return null; } } - boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); - CompletableFuture resultFuture = new CompletableFuture<>(); RpcContext rpcContext = RpcContext.getContext(); + boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); if (supportServerAsync) { - rpcContext.setAsyncContext(new AsyncContextImpl(resultFuture)); + CompletableFuture future = new CompletableFuture<>(); + rpcContext.setAsyncContext(new AsyncContextImpl(future)); } rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); - if (!rpcContext.isAsyncStarted()) { - resultFuture.complete(result); - } else if (rpcContext.isAsyncStarted() && result.hasException()) { - if (rpcContext.stopAsync()) { - resultFuture.complete(result); - } - } - return resultFuture; + if (result instanceof AsyncRpcResult) { + return ((AsyncRpcResult) result).getResultFuture().thenApply(r -> (Object) r); + } else { + return CompletableFuture.completedFuture(result); + } } throw new RemotingException(channel, "Unsupported request: " + (message == null ? null : (message.getClass().getName() + ": " + message)) diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java deleted file mode 100644 index 29254db3b57..00000000000 --- a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ThriftProtocol.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.dubbo.rpc.protocol.thrift; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.common.extension.ExtensionLoader; -import com.alibaba.dubbo.common.utils.ConfigUtils; -import com.alibaba.dubbo.remoting.Channel; -import com.alibaba.dubbo.remoting.RemotingException; -import com.alibaba.dubbo.remoting.Transporter; -import com.alibaba.dubbo.remoting.exchange.ExchangeChannel; -import com.alibaba.dubbo.remoting.exchange.ExchangeClient; -import com.alibaba.dubbo.remoting.exchange.ExchangeHandler; -import com.alibaba.dubbo.remoting.exchange.ExchangeServer; -import com.alibaba.dubbo.remoting.exchange.Exchangers; -import com.alibaba.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import com.alibaba.dubbo.rpc.Exporter; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.RpcContext; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.protocol.AbstractProtocol; -import com.alibaba.dubbo.rpc.protocol.dubbo.DubboExporter; - -import java.util.ArrayList; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -public class ThriftProtocol extends AbstractProtocol { - - public static final int DEFAULT_PORT = 40880; - - public static final String NAME = "thrift"; - - // ip:port -> ExchangeServer - private final ConcurrentMap serverMap = - new ConcurrentHashMap(); - - private ExchangeHandler handler = new ExchangeHandlerAdapter() { - - @Override - public CompletableFuture reply(ExchangeChannel channel, Object msg) throws RemotingException { - - if (msg instanceof Invocation) { - Invocation inv = (Invocation) msg; - String serviceName = inv.getAttachments().get(Constants.INTERFACE_KEY); - String serviceKey = serviceKey(channel.getLocalAddress().getPort(), - serviceName, null, null); - DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey); - if (exporter == null) { - throw new RemotingException(channel, - "Not found exported service: " - + serviceKey - + " in " - + exporterMap.keySet() - + ", may be version or group mismatch " - + ", channel: consumer: " - + channel.getRemoteAddress() - + " --> provider: " - + channel.getLocalAddress() - + ", message:" + msg); - } - - RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress()); - - return CompletableFuture.completedFuture(exporter.getInvoker().invoke(inv)); - - } - - throw new RemotingException(channel, - "Unsupported request: " - + (msg.getClass().getName() + ": " + msg) - + ", channel: consumer: " - + channel.getRemoteAddress() - + " --> provider: " - + channel.getLocalAddress()); - } - - @Override - public void received(Channel channel, Object message) throws RemotingException { - if (message instanceof Invocation) { - reply((ExchangeChannel) channel, message); - } else { - super.received(channel, message); - } - } - - }; - - @Override - public int getDefaultPort() { - return DEFAULT_PORT; - } - - @Override - public Exporter export(Invoker invoker) throws RpcException { - - // can use thrift codec only - URL url = invoker.getUrl().addParameter(Constants.CODEC_KEY, ThriftCodec.NAME); - // find server. - String key = url.getAddress(); - // client can expose a service for server to invoke only. - boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true); - if (isServer && !serverMap.containsKey(key)) { - serverMap.put(key, getServer(url)); - } - // export service. - key = serviceKey(url); - DubboExporter exporter = new DubboExporter(invoker, key, exporterMap); - exporterMap.put(key, exporter); - - return exporter; - } - - @Override - public void destroy() { - - super.destroy(); - - for (String key : new ArrayList(serverMap.keySet())) { - - ExchangeServer server = serverMap.remove(key); - - if (server != null) { - try { - if (logger.isInfoEnabled()) { - logger.info("Close dubbo server: " + server.getLocalAddress()); - } - server.close(ConfigUtils.getServerShutdownTimeout()); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - } // ~ end of if ( server != null ) - - } // ~ end of loop serverMap - - } // ~ end of method destroy - - @Override - public Invoker refer(Class type, URL url) throws RpcException { - - ThriftInvoker invoker = new ThriftInvoker(type, url, getClients(url), invokers); - - invokers.add(invoker); - - return invoker; - - } - - private ExchangeClient[] getClients(URL url) { - - int connections = url.getParameter(Constants.CONNECTIONS_KEY, 1); - - ExchangeClient[] clients = new ExchangeClient[connections]; - - for (int i = 0; i < clients.length; i++) { - clients[i] = initClient(url); - } - return clients; - } - - private ExchangeClient initClient(URL url) { - - ExchangeClient client; - - url = url.addParameter(Constants.CODEC_KEY, ThriftCodec.NAME); - - try { - client = Exchangers.connect(url); - } catch (RemotingException e) { - throw new RpcException("Fail to create remoting client for service(" + url - + "): " + e.getMessage(), e); - } - - return client; - - } - - private ExchangeServer getServer(URL url) { - // enable sending readonly event when server closes by default - url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()); - String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); - - if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) - throw new RpcException("Unsupported server type: " + str + ", url: " + url); - - ExchangeServer server; - try { - server = Exchangers.bind(url, handler); - } catch (RemotingException e) { - throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e); - } - str = url.getParameter(Constants.CLIENT_KEY); - if (str != null && str.length() > 0) { - Set supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(); - if (!supportedTypes.contains(str)) { - throw new RpcException("Unsupported client type: " + str); - } - } - return server; - } - -} diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java index 81b7f028164..4f089237674 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java @@ -42,7 +42,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; - public class ThriftProtocol extends AbstractProtocol { public static final int DEFAULT_PORT = 40880; diff --git a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java index 7c747717ef9..fa6e3749249 100644 --- a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java +++ b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java @@ -19,6 +19,8 @@ import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.demo.DemoService; +import java.util.concurrent.CompletableFuture; + /** * Default {@link DemoService} implementation * @@ -37,4 +39,9 @@ public String sayHello(String name) { return "DefaultDemoService - sayHell() : " + name; } + @Override + public CompletableFuture originalFuture(String name) { + return null; + } + } From 321bf46a7c4d0b64775958b9b6303f1b86a26d90 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Sun, 17 Jun 2018 12:31:20 +0800 Subject: [PATCH 28/39] support context switch & optimization --- .../apache/dubbo/demo/consumer/Consumer.java | 2 +- .../dubbo/rpc/AbstractPostProcessFilter.java | 35 ++++++++ .../apache/dubbo/rpc/AsyncContextImpl.java | 10 ++- .../org/apache/dubbo/rpc/AsyncRpcResult.java | 85 +++++++++++++++++-- .../apache/dubbo/rpc/PostProcessFilter.java | 2 +- .../java/org/apache/dubbo/rpc/Result.java | 2 + .../java/org/apache/dubbo/rpc/RpcContext.java | 15 +++- .../java/org/apache/dubbo/rpc/RpcResult.java | 4 +- .../rpc/filter/ConsumerContextFilter.java | 13 +-- .../dubbo/rpc/filter/ContextFilter.java | 21 +++-- .../dubbo/rpc/filter/ExceptionFilter.java | 19 ++--- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 3 +- .../rpc/protocol/dubbo/DubboInvoker.java | 6 +- .../rpc/protocol/dubbo/FutureAdapter.java | 12 +++ 14 files changed, 185 insertions(+), 44 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractPostProcessFilter.java diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java index 05cc9702db2..14384a36e7a 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws InterruptedException { e.printStackTrace(); } -// System.out.println(demoService.sayHello("world")); + System.out.println(demoService.sayHello("world")); try { CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); System.out.println(generatedFuture.get()); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractPostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractPostProcessFilter.java new file mode 100644 index 00000000000..f7034b0bde6 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AbstractPostProcessFilter.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc; + +/** + * + */ +public abstract class AbstractPostProcessFilter implements PostProcessFilter { + @Override + public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { + if (result instanceof AsyncRpcResult) { + AsyncRpcResult asyncResult = (AsyncRpcResult) result; + asyncResult.thenApplyWithContext(r -> doPostProcess(r, invoker, invocation)); + return asyncResult; + } else { + return doPostProcess(result, invoker, invocation); + } + } + + protected abstract Result doPostProcess(Result result, Invoker invoker, Invocation invocation); +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java index 198633db14c..a0cf38b305d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java @@ -28,11 +28,16 @@ public class AsyncContextImpl implements AsyncContext { private CompletableFuture future; + private RpcContext storedContext; + private RpcContext storedServerContext; + public AsyncContextImpl() { } public AsyncContextImpl(CompletableFuture future) { this.future = future; + this.storedContext = RpcContext.getContext(); + this.storedServerContext = RpcContext.getServerContext(); } @Override @@ -72,9 +77,10 @@ public void start() { this.started.set(true); } - @Override public void signalContextSwitch() { - + RpcContext.restoreContext(storedContext); + RpcContext.restoreServerContext(storedServerContext); + // Restore any other contexts in here if necessary. } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java index 8cd1f67ba02..c09ceb781ec 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java @@ -19,16 +19,21 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.function.Function; public class AsyncRpcResult extends AbstractResult { private static final Logger logger = LoggerFactory.getLogger(AsyncRpcResult.class); - private Map attachments = new HashMap(); + /** + * 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. + */ + private RpcContext storedContext; + private RpcContext storedServerContext; protected CompletableFuture valueFuture; @@ -39,12 +44,26 @@ public AsyncRpcResult(CompletableFuture future) { } public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { - if (registerCallback) { + this(future, null, registerCallback); + } + + /** + * @param future + * @param rFuture + * @param registerCallback + */ + public AsyncRpcResult(CompletableFuture future, CompletableFuture rFuture, boolean registerCallback) { + + if (rFuture == null) { resultFuture = new CompletableFuture<>(); + } else { + 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, is Dubbo thread. - * 2. future complete after whenComplete. whenComplete fn (resultFuture.complete) will be executed in thread calling complete, normally is User thread. + * 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; @@ -61,6 +80,7 @@ public AsyncRpcResult(CompletableFuture future, boolean registerCallback }); } this.valueFuture = future; + this.storedContext = RpcContext.getContext(); } @Override @@ -111,5 +131,60 @@ public Result getRpcResult() { public Object recreate() throws Throwable { return valueFuture; } + + public void thenApplyWithContext(Function fn) { + this.setResultFuture( + resultFuture.thenApply(fn.compose(beforeContext).andThen(afterContext)) + ); + } + + @Override + public Map getAttachments() { + return getRpcResult().getAttachments(); + } + + @Override + public void setAttachments(Map map) { + getRpcResult().setAttachments(map); + } + + @Override + public void addAttachments(Map map) { + getRpcResult().addAttachments(map); + } + + @Override + public String getAttachment(String key) { + return getRpcResult().getAttachment(key); + } + + @Override + public String getAttachment(String key, String defaultValue) { + return getRpcResult().getAttachment(key, defaultValue); + } + + public void setAttachment(String key, String value) { + getRpcResult().setAttachment(key, value); + } + + /** + * + */ + private RpcContext tmpContext; + private RpcContext tmpServerContext; + + private Function beforeContext = (result) -> { + tmpContext = RpcContext.getContext(); + tmpServerContext = RpcContext.getServerContext(); + RpcContext.restoreContext(storedContext); + RpcContext.restoreServerContext(storedServerContext); + return result; + }; + + private Function afterContext = (result) -> { + RpcContext.restoreContext(tmpContext); + RpcContext.restoreServerContext(tmpServerContext); + return result; + }; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java index e0a0c2dbe44..c92625c668f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/PostProcessFilter.java @@ -21,7 +21,7 @@ */ public interface PostProcessFilter extends Filter { /** - * TODO Filter is singleton, so we have to add invoker & invocation as parameters for every invoke. + * TODO Filter is singleton, so we have to add invoker & invocation as parameters for every invoke. But think of prototype, we may need to restore invocation between threads, because we will lost 'closure'. * * @param result * @param invoker diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java index e2b652116d4..a5bb4da9847 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java @@ -109,4 +109,6 @@ public interface Result extends Serializable { */ String getAttachment(String key, String defaultValue); + void setAttachment(String key, String value); + } \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index efef6885776..f196228626e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -44,7 +44,7 @@ * starts invoking C, and saves invocation info from B to C after B invokes C. * * @export - * @see com.alibaba.dubbo.rpc.filter.ContextFilter + * @see org.apache.dubbo.rpc.filter.ContextFilter */ public class RpcContext { @@ -106,10 +106,14 @@ public static RpcContext getServerContext() { return SERVER_LOCAL.get(); } + public static void restoreServerContext(RpcContext oldServerContext) { + LOCAL.set(oldServerContext); + } + /** * remove server side context. * - * @see com.alibaba.dubbo.rpc.filter.ContextFilter + * @see org.apache.dubbo.rpc.filter.ContextFilter */ public static void removeServerContext() { SERVER_LOCAL.remove(); @@ -124,10 +128,14 @@ public static RpcContext getContext() { return LOCAL.get(); } + public static void restoreContext(RpcContext oldContext) { + LOCAL.set(oldContext); + } + /** * remove context. * - * @see com.alibaba.dubbo.rpc.filter.ContextFilter + * @see org.apache.dubbo.rpc.filter.ContextFilter */ public static void removeContext() { LOCAL.remove(); @@ -728,4 +736,5 @@ public void setAsyncContext(AsyncContext asyncContext) { public AsyncContext getAsyncContext() { return asyncContext; } + } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java index cca7b365f31..3f27420021d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcResult.java @@ -45,7 +45,7 @@ public Object recreate() throws Throwable { } /** - * @see com.alibaba.dubbo.rpc.RpcResult#getValue() + * @see org.apache.dubbo.rpc.RpcResult#getValue() * @deprecated Replace to getValue() */ @Override @@ -55,7 +55,7 @@ public Object getResult() { } /** - * @see com.alibaba.dubbo.rpc.RpcResult#setValue(Object) + * @see org.apache.dubbo.rpc.RpcResult#setValue(Object) * @deprecated Replace to setValue() */ @Deprecated diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java index daba2f5f6d4..9cf9fd6426d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @@ -19,7 +19,7 @@ import org.apache.dubbo.common.Constants; 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.AbstractPostProcessFilter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; @@ -31,7 +31,7 @@ * ConsumerContextInvokerFilter */ @Activate(group = Constants.CONSUMER, order = -10000) -public class ConsumerContextFilter implements Filter { +public class ConsumerContextFilter extends AbstractPostProcessFilter { @Override public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { @@ -45,12 +45,15 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - Result result = invoker.invoke(invocation); - RpcContext.getServerContext().setAttachments(result.getAttachments()); - return result; + return postProcessResult(invoker.invoke(invocation), invoker, invocation); } finally { RpcContext.getContext().clearAttachments(); } } + @Override + protected Result doPostProcess(Result result, Invoker invoker, Invocation invocation) { + RpcContext.getServerContext().setAttachments(result.getAttachments()); + return result; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java index a38fbb06793..8b05711a3d1 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java @@ -18,7 +18,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.AbstractPostProcessFilter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; @@ -33,7 +33,7 @@ * ContextInvokerFilter */ @Activate(group = Constants.PROVIDER, order = -10000) -public class ContextFilter implements Filter { +public class ContextFilter extends AbstractPostProcessFilter { @Override public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { @@ -57,6 +57,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept // mreged from dubbox // we may already added some attachments into RpcContext before this filter (e.g. in rest protocol) + // TODO if (attachments != null) { if (RpcContext.getContext().getAttachments() != null) { RpcContext.getContext().getAttachments().putAll(attachments); @@ -69,14 +70,18 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { - Result result = invoker.invoke(invocation); - // pass attachments to result - result.addAttachments(RpcContext.getServerContext().getAttachments()); - return result; + return postProcessResult(invoker.invoke(invocation), invoker, invocation); } finally { - // TODO must we remove the whole context completely? + // IMPORTANT! For async scenario, we must remove context from current thread, so we always create a new RpcContext for the next invoke for the same thread. RpcContext.removeContext(); - RpcContext.getServerContext().clearAttachments(); + RpcContext.removeServerContext(); } } + + @Override + protected Result doPostProcess(Result result, Invoker invoker, Invocation invocation) { + // pass attachments to result + result.addAttachments(RpcContext.getServerContext().getAttachments()); + return result; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java index eb36be28a02..5cb047a5639 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java @@ -22,10 +22,9 @@ 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.AsyncRpcResult; +import org.apache.dubbo.rpc.AbstractPostProcessFilter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.PostProcessFilter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; @@ -33,7 +32,6 @@ import org.apache.dubbo.rpc.service.GenericService; import java.lang.reflect.Method; -import java.util.concurrent.CompletableFuture; /** @@ -47,7 +45,7 @@ * */ @Activate(group = Constants.PROVIDER) -public class ExceptionFilter implements PostProcessFilter { +public class ExceptionFilter extends AbstractPostProcessFilter { private final Logger logger; @@ -62,15 +60,7 @@ public ExceptionFilter(Logger logger) { @Override public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { try { - Result result = invoker.invoke(invocation); - if (result instanceof AsyncRpcResult) { - AsyncRpcResult asyncResult = (AsyncRpcResult) result; - CompletableFuture future = asyncResult.getResultFuture(); - asyncResult.setResultFuture(future.thenApply(r -> postProcessResult(r, invoker, invocation))); - return asyncResult; - } else { - return postProcessResult(result, invoker, invocation); - } + return postProcessResult(invoker.invoke(invocation), invoker, invocation); } catch (RuntimeException e) { logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() @@ -79,7 +69,8 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept } } - public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { + @Override + protected Result doPostProcess(Result result, Invoker invoker, Invocation invocation) { if (result.hasException() && GenericService.class != invoker.getInterface()) { try { Throwable exception = result.getException(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java index ae2ac71651f..b208325d192 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -78,11 +78,12 @@ public void destroy() { @Override public Result invoke(Invocation invocation) throws RpcException { try { + RpcContext rpcContext = RpcContext.getContext(); Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); if (RpcUtils.isFutureReturnType(invocation)) { return new AsyncRpcResult((CompletableFuture) obj); } else if (RpcContext.getContext().isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. - return new AsyncRpcResult(RpcContext.getContext().getAsyncContext().getInternalFuture()); + return new AsyncRpcResult(rpcContext.getAsyncContext().getInternalFuture()); } else { return new RpcResult(obj); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 5e4c406e4ca..d01cd26b719 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -90,12 +90,14 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { return new RpcResult(); } else if (isAsync) { ResponseFuture future = currentClient.request(inv, timeout); + // For compatibility FutureAdapter futureAdapter = new FutureAdapter<>(future); RpcContext.getContext().setFuture(futureAdapter); + Result result; if (isAsyncFuture) { - // register resultCallback, sometimes we need the result being processed in the filter chain. - result = new AsyncRpcResult(futureAdapter, true); + // register resultCallback, sometimes we need the asyn result being processed by the filter chain. + result = new AsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false); } else { result = new RpcResult(); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java index ca9ecc72c7b..addb3b34d5d 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java @@ -34,6 +34,7 @@ public class FutureAdapter extends CompletableFuture { private final ResponseFuture future; + private CompletableFuture resultFuture; public FutureAdapter(ResponseFuture future) { this.future = future; @@ -41,6 +42,7 @@ public FutureAdapter(ResponseFuture future) { @Override public void done(Object response) { Result result = (Result) response; + FutureAdapter.this.resultFuture = CompletableFuture.completedFuture(result); V value = null; try { value = (V) result.recreate(); @@ -103,5 +105,15 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution } } + /** + * FIXME + * This method has no need open to the the end user. + * Mostly user use RpcContext.getFuture() to refer the instance of this class, so the user will get a CompletableFuture, this method will rarely be noticed. + * + * @return + */ + public CompletableFuture getResultFuture() { + return resultFuture; + } } From 2a6a0b4f362cc3450b1d56806109c19238b106cd Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 18 Jun 2018 01:26:00 +0800 Subject: [PATCH 29/39] fix several bugs: context restore, consumer callback --- .../org/apache/dubbo/rpc/AsyncRpcResult.java | 16 ++++++------ .../java/org/apache/dubbo/rpc/RpcContext.java | 2 +- .../rpc/filter/ConsumerContextFilter.java | 4 ++- .../rpc/protocol/dubbo/FutureAdapter.java | 22 +++++++--------- .../protocol/dubbo/filter/FutureFilter.java | 25 ++++++++++++------- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java index c09ceb781ec..82c4e303102 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java @@ -44,7 +44,7 @@ public AsyncRpcResult(CompletableFuture future) { } public AsyncRpcResult(CompletableFuture future, boolean registerCallback) { - this(future, null, registerCallback); + this(future, new CompletableFuture<>(), registerCallback); } /** @@ -53,12 +53,10 @@ public AsyncRpcResult(CompletableFuture future, boolean registerCallback * @param registerCallback */ public AsyncRpcResult(CompletableFuture future, CompletableFuture rFuture, boolean registerCallback) { - if (rFuture == null) { - resultFuture = new CompletableFuture<>(); - } else { - resultFuture = rFuture; + 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. @@ -76,11 +74,13 @@ public AsyncRpcResult(CompletableFuture future, CompletableFuture fn) { - this.setResultFuture( - resultFuture.thenApply(fn.compose(beforeContext).andThen(afterContext)) - ); + this.resultFuture = resultFuture.thenApply(fn.compose(beforeContext).andThen(afterContext)); } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index f196228626e..069c7a7108d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -107,7 +107,7 @@ public static RpcContext getServerContext() { } public static void restoreServerContext(RpcContext oldServerContext) { - LOCAL.set(oldServerContext); + SERVER_LOCAL.set(oldServerContext); } /** diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java index 9cf9fd6426d..815f707baa5 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @@ -45,9 +45,11 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept ((RpcInvocation) invocation).setInvoker(invoker); } try { + // TODO should we clear server context? + RpcContext.removeServerContext(); return postProcessResult(invoker.invoke(invocation), invoker, invocation); } finally { - RpcContext.getContext().clearAttachments(); + RpcContext.removeContext(); } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java index addb3b34d5d..e025cbddc5f 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/FutureAdapter.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.dubbo; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.remoting.RemotingException; import org.apache.dubbo.remoting.exchange.ResponseCallback; import org.apache.dubbo.remoting.exchange.ResponseFuture; import org.apache.dubbo.rpc.Result; @@ -38,11 +36,12 @@ public class FutureAdapter extends CompletableFuture { public FutureAdapter(ResponseFuture future) { this.future = future; + this.resultFuture = new CompletableFuture<>(); future.setCallback(new ResponseCallback() { @Override public void done(Object response) { Result result = (Result) response; - FutureAdapter.this.resultFuture = CompletableFuture.completedFuture(result); + FutureAdapter.this.resultFuture.complete(result); V value = null; try { value = (V) result.recreate(); @@ -75,16 +74,16 @@ public boolean isCancelled() { @Override public boolean isDone() { - return future.isDone(); + return this.isDone(); } @Override @SuppressWarnings("unchecked") public V get() throws InterruptedException, ExecutionException { try { - return (V) (((Result) future.get()).recreate()); - } catch (RemotingException e) { - throw new ExecutionException(e.getMessage(), e); + return super.get(); + } catch (ExecutionException | InterruptedException e) { + throw e; } catch (Throwable e) { throw new RpcException(e); } @@ -93,13 +92,10 @@ public V get() throws InterruptedException, ExecutionException { @Override @SuppressWarnings("unchecked") public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - int timeoutInMillis = (int) TimeUnit.MILLISECONDS.convert(timeout, unit); try { - return (V) (((Result) future.get(timeoutInMillis)).recreate()); - } catch (org.apache.dubbo.remoting.TimeoutException e) { - throw new TimeoutException(StringUtils.toString(e)); - } catch (RemotingException e) { - throw new ExecutionException(e.getMessage(), e); + return super.get(timeout, unit); + } catch (TimeoutException | ExecutionException | InterruptedException e) { + throw e; } catch (Throwable e) { throw new RpcException(e); } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java index c30281ac824..19b22784838 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java @@ -22,15 +22,15 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.remoting.exchange.ResponseCallback; import org.apache.dubbo.remoting.exchange.ResponseFuture; -import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.PostProcessFilter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.StaticContext; import org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter; -import org.apache.dubbo.rpc.support.RpcUtils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -40,24 +40,31 @@ * EventFilter */ @Activate(group = Constants.CONSUMER) -public class FutureFilter implements Filter { +public class FutureFilter implements PostProcessFilter { protected static final Logger logger = LoggerFactory.getLogger(FutureFilter.class); @Override public Result invoke(final Invoker invoker, final Invocation invocation) throws RpcException { - final boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation); - fireInvokeCallback(invoker, invocation); // need to configure if there's return value before the invocation in order to help invoker to judge if it's // necessary to return future. - Result result = invoker.invoke(invocation); - if (isAsync) { - asyncCallback(invoker, invocation); + return postProcessResult(invoker.invoke(invocation), invoker, invocation); + } + + @Override + public Result postProcessResult(Result result, Invoker invoker, Invocation invocation) { + if (result instanceof AsyncRpcResult) { + AsyncRpcResult asyncResult = (AsyncRpcResult) result; + asyncResult.thenApplyWithContext(r -> { + asyncCallback(invoker, invocation); + return r; + }); + return asyncResult; } else { syncCallback(invoker, invocation, result); + return result; } - return result; } private void syncCallback(final Invoker invoker, final Invocation invocation, final Result result) { From c0d79d6a511b343c60ae697d6c765da3bec84c0b Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 18 Jun 2018 03:02:45 +0800 Subject: [PATCH 30/39] consumerFilter: clear attachments instead of remove context --- .../org/apache/dubbo/rpc/filter/ConsumerContextFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java index 815f707baa5..4b0acd70279 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @@ -49,7 +49,8 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept RpcContext.removeServerContext(); return postProcessResult(invoker.invoke(invocation), invoker, invocation); } finally { - RpcContext.removeContext(); + // TODO removeContext? but we need to save future for API RpcContext.getFuture(). Clear attachments here, attachments are not available in postProcessResult. + RpcContext.getContext().clearAttachments(); } } From 14ed6a37b9f99ee0cb8f6d38a8751d18609dc2e2 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 18 Jun 2018 22:23:40 +0800 Subject: [PATCH 31/39] change async API in RpcContext to CompletableFuture. --- .../java/org/apache/dubbo/rpc/RpcContext.java | 21 +++++++------------ .../rpc/filter/ConsumerContextFilter.java | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index 069c7a7108d..598b57d3f44 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -31,7 +31,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -628,23 +627,19 @@ public RpcContext setInvocation(Invocation invocation) { * @return get the return result from future.get() */ @SuppressWarnings("unchecked") - public Future asyncCall(Callable callable) { + public CompletableFuture asyncCall(Callable callable) { try { try { setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString()); final T o = callable.call(); //local invoke will return directly if (o != null) { - FutureTask f = new FutureTask(new Callable() { - @Override - public T call() throws Exception { - return o; - } - }); - f.run(); - return f; + if (o instanceof CompletableFuture) { + return (CompletableFuture) o; + } + CompletableFuture.completedFuture(o); } else { - + // The service has a normal sync method signature, should get future from RpcContext. } } catch (Exception e) { throw new RpcException(e); @@ -652,7 +647,7 @@ public T call() throws Exception { removeAttachment(Constants.ASYNC_KEY); } } catch (final RpcException e) { - return new Future() { + return new CompletableFuture() { @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; @@ -681,7 +676,7 @@ public T get(long timeout, TimeUnit unit) } }; } - return ((Future) getContext().getFuture()); + return ((CompletableFuture) getContext().getFuture()); } /** diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java index 4b0acd70279..f852d7b9e96 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ConsumerContextFilter.java @@ -49,7 +49,7 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept RpcContext.removeServerContext(); return postProcessResult(invoker.invoke(invocation), invoker, invocation); } finally { - // TODO removeContext? but we need to save future for API RpcContext.getFuture(). Clear attachments here, attachments are not available in postProcessResult. + // 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(); } } From 063a80ea43466a26a474ae8d84a95ee62ce35664 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 18 Jun 2018 23:18:16 +0800 Subject: [PATCH 32/39] Delete demo codes --- dubbo-demo/dubbo-demo-api/pom.xml | 7 ---- .../org/apache/dubbo/demo/DemoService.java | 3 -- .../apache/dubbo/demo/DemoServiceAsync.java | 29 ---------------- .../apache/dubbo/demo/consumer/Consumer.java | 26 ++++----------- .../META-INF/spring/dubbo-demo-consumer.xml | 4 +-- .../dubbo/demo/provider/DemoServiceImpl.java | 33 ------------------- .../META-INF/spring/dubbo-demo-provider.xml | 4 +-- 7 files changed, 10 insertions(+), 96 deletions(-) delete mode 100644 dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index 84c2ee97ee6..a9179b55034 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -28,11 +28,4 @@ true - - - - com.alibaba - dubbo-common - - \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java index 656413c83b0..1172c9be0fc 100644 --- a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java +++ b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoService.java @@ -16,11 +16,8 @@ */ package org.apache.dubbo.demo; -import java.util.concurrent.CompletableFuture; - public interface DemoService { String sayHello(String name); - CompletableFuture originalFuture(String name); } \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java b/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java deleted file mode 100644 index 5027e7e175d..00000000000 --- a/dubbo-demo/dubbo-demo-api/src/main/java/org/apache/dubbo/demo/DemoServiceAsync.java +++ /dev/null @@ -1,29 +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.demo; - -import org.apache.dubbo.common.config.AsyncFor; - -import java.util.concurrent.CompletableFuture; - -/** - * - */ -@AsyncFor(DemoService.class) -public interface DemoServiceAsync extends DemoService { - CompletableFuture sayHelloAsync(String name); -} diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java index 14384a36e7a..03e9a1a9e22 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java +++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java @@ -17,42 +17,30 @@ package org.apache.dubbo.demo.consumer; import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.demo.DemoServiceAsync; import org.springframework.context.support.ClassPathXmlApplicationContext; -import java.util.concurrent.CompletableFuture; - public class Consumer { - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) { //Prevent to get IPV6 address,this way only work in debug mode //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not System.setProperty("java.net.preferIPv4Stack", "true"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"}); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy - DemoServiceAsync demoServiceAsync = (DemoServiceAsync) context.getBean("demoServiceAsync"); while (true) { try { - try { - CompletableFuture future = demoService.originalFuture("world"); // call remote method - System.out.println(future.get()); // get result - } catch (Exception e) { - e.printStackTrace(); - } - - System.out.println(demoService.sayHello("world")); - try { - CompletableFuture generatedFuture = demoServiceAsync.sayHelloAsync("generated async"); - System.out.println(generatedFuture.get()); - } catch (Exception e) { - e.printStackTrace(); - } Thread.sleep(1000); + String hello = demoService.sayHello("world"); // call remote method + System.out.println(hello); // get result + } catch (Throwable throwable) { throwable.printStackTrace(); } + + } + } } diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml index a6f0c06283a..a56a10ee7ea 100644 --- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml +++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml @@ -26,12 +26,10 @@ - + - - \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java index 007f399a1a0..004f48d98bc 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java @@ -17,50 +17,17 @@ package org.apache.dubbo.demo.provider; import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.rpc.AsyncContext; import org.apache.dubbo.rpc.RpcContext; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.concurrent.CompletableFuture; - public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - startAsync(name); -// throw new RuntimeException("bbb"); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } - @Override - public CompletableFuture originalFuture(String name) { - return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } -// throw new RuntimeException("aaa"); - return "test Async"; - }); - } - - private void startAsync(String name) { - AsyncContext asyncContext = RpcContext.startAsync(); - new Thread(() -> { - System.out.println(" -- Async start."); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - asyncContext.write("Hello " + name + ", response from async provider."); - System.out.println(" -- Async end."); - }).start(); - } - } - diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml index d5b105dcebf..c2ab4a21e01 100644 --- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml +++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml @@ -25,7 +25,7 @@ - + @@ -34,6 +34,6 @@ - + \ No newline at end of file From 63db2d86e50f31aa008cc8b0118514c6ec833025 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 19 Jun 2018 09:43:21 +0800 Subject: [PATCH 33/39] fix compilation problem --- .../org/apache/dubbo/test/provider/DefaultDemoService.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java index fa6e3749249..7c747717ef9 100644 --- a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java +++ b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java @@ -19,8 +19,6 @@ import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.demo.DemoService; -import java.util.concurrent.CompletableFuture; - /** * Default {@link DemoService} implementation * @@ -39,9 +37,4 @@ public String sayHello(String name) { return "DefaultDemoService - sayHell() : " + name; } - @Override - public CompletableFuture originalFuture(String name) { - return null; - } - } From 71a2206c5e6952b61657bb801fe65c3f25353804 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 19 Jun 2018 13:11:29 +0800 Subject: [PATCH 34/39] Fix RpcUtils, get the right method return type. --- .../apache/dubbo/rpc/support/RpcUtils.java | 15 +++-- .../apache/dubbo/rpc/support/DemoService.java | 16 ++++++ .../dubbo/rpc/support/DemoServiceImpl.java | 34 ++++++++++++ .../dubbo/rpc/support/RpcUtilsTest.java | 55 ++++++++++++++++++- 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java index f543181350e..077970ad292 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/RpcUtils.java @@ -80,11 +80,18 @@ public static Type[] getReturnTypes(Invocation invocation) { Type genericReturnType = method.getGenericReturnType(); if (Future.class.isAssignableFrom(returnType)) { if (genericReturnType instanceof ParameterizedType) { - returnType = (Class) ((ParameterizedType) genericReturnType).getActualTypeArguments()[0]; + 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; } - genericReturnType = returnType; // TODO Can we handle nested generic? for example CompletableFuture> - } else { - genericReturnType = returnType; } return new Type[]{returnType, genericReturnType}; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoService.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoService.java index b84f379f402..435599a35dc 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoService.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoService.java @@ -18,6 +18,10 @@ import org.apache.dubbo.rpc.CustomArgument; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + public interface DemoService { void sayHello(String name); @@ -43,4 +47,16 @@ public interface DemoService { byte getbyte(byte arg); + String testReturnType(String str); + + List testReturnType1(String str); + + CompletableFuture testReturnType2(String str); + + CompletableFuture> testReturnType3(String str); + + CompletableFuture testReturnType4(String str); + + CompletableFuture> testReturnType5(String str); + } \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoServiceImpl.java index b2355ac35d6..956ec4607d9 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/DemoServiceImpl.java @@ -19,6 +19,10 @@ import org.apache.dubbo.rpc.CustomArgument; import org.apache.dubbo.rpc.RpcContext; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + /** * DemoServiceImpl */ @@ -83,6 +87,36 @@ public byte getbyte(byte arg) { return arg; } + @Override + public String testReturnType(String str) { + return null; + } + + @Override + public List testReturnType1(String str) { + return null; + } + + @Override + public CompletableFuture testReturnType2(String str) { + return null; + } + + @Override + public CompletableFuture> testReturnType3(String str) { + return null; + } + + @Override + public CompletableFuture testReturnType4(String str) { + return CompletableFuture.completedFuture(""); + } + + @Override + public CompletableFuture> testReturnType5(String str) { + return null; + } + public Person gerPerson(Person person) { return person; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/RpcUtilsTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/RpcUtilsTest.java index 01859cac0be..cbe17e47255 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/RpcUtilsTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/RpcUtilsTest.java @@ -19,17 +19,22 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcInvocation; - +import org.junit.Assert; import org.junit.Test; +import java.lang.reflect.ParameterizedType; import java.util.HashMap; +import java.util.List; import java.util.Map; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; public class RpcUtilsTest { @@ -99,4 +104,48 @@ public void testAttachInvocationIdIfAsync_forceAttache() { RpcUtils.attachInvocationIdIfAsync(url, inv); assertNotNull(RpcUtils.getInvocationId(inv)); } + + @Test + public void testGetReturnTypes() throws Exception { + Invoker invoker = mock(Invoker.class); + given(invoker.getUrl()).willReturn(URL.valueOf("test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService")); + Invocation inv = new RpcInvocation("testReturnType", new Class[]{String.class}, null, null, invoker); + + java.lang.reflect.Type[] types = RpcUtils.getReturnTypes(inv); + Assert.assertEquals(2, types.length); + Assert.assertEquals(String.class, types[0]); + Assert.assertEquals(String.class, types[1]); + + Invocation inv1 = new RpcInvocation("testReturnType1", new Class[]{String.class}, null, null, invoker); + java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1); + Assert.assertEquals(2, types1.length); + Assert.assertEquals(List.class, types1[0]); + Assert.assertEquals(DemoService.class.getMethod("testReturnType1", new Class[]{String.class}).getGenericReturnType(), types1[1]); + + Invocation inv2 = new RpcInvocation("testReturnType2", new Class[]{String.class}, null, null, invoker); + java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2); + Assert.assertEquals(2, types2.length); + Assert.assertEquals(String.class, types2[0]); + Assert.assertEquals(String.class, types2[1]); + + Invocation inv3 = new RpcInvocation("testReturnType3", new Class[]{String.class}, null, null, invoker); + java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3); + Assert.assertEquals(2, types3.length); + Assert.assertEquals(List.class, types3[0]); + java.lang.reflect.Type genericReturnType3 = DemoService.class.getMethod("testReturnType3", new Class[]{String.class}).getGenericReturnType(); + Assert.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]); + + Invocation inv4 = new RpcInvocation("testReturnType4", new Class[]{String.class}, null, null, invoker); + java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4); + Assert.assertEquals(2, types4.length); + Assert.assertEquals(null, types4[0]); + Assert.assertEquals(null, types4[1]); + + Invocation inv5 = new RpcInvocation("testReturnType5", new Class[]{String.class}, null, null, invoker); + java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5); + Assert.assertEquals(2, types5.length); + Assert.assertEquals(Map.class, types5[0]); + java.lang.reflect.Type genericReturnType5 = DemoService.class.getMethod("testReturnType5", new Class[]{String.class}).getGenericReturnType(); + Assert.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]); + } } From 84b8b48ec09651f5f0c291f9d522e90ea0b1daf6 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 19 Jun 2018 16:11:33 +0800 Subject: [PATCH 35/39] unified to AsyncRpcResult on consumer side. --- .../dubbo/rpc/SimpleAsyncRpcResult.java | 39 ++++++++++++++++++ .../rpc/protocol/dubbo/DubboInvoker.java | 3 +- .../protocol/dubbo/filter/FutureFilter.java | 41 +++---------------- 3 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java new file mode 100644 index 00000000000..49a492b1ceb --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc; + +import java.util.concurrent.CompletableFuture; + +/** + * A sub class used for normal async invoke. + * TODO AsyncRpcResult, AsyncNormalRpcResult should not be a parent-child hierarchy. + */ +public class SimpleAsyncRpcResult extends AsyncRpcResult { + public SimpleAsyncRpcResult(CompletableFuture future, boolean registerCallback) { + super(future, registerCallback); + } + + public SimpleAsyncRpcResult(CompletableFuture future, CompletableFuture rFuture, boolean registerCallback) { + super(future, rFuture, registerCallback); + } + + @Override + public Object recreate() throws Throwable { + // TODO should we check the status of valueFuture here? + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java index d01cd26b719..7c574ffb856 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -32,6 +32,7 @@ import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcResult; +import org.apache.dubbo.rpc.SimpleAsyncRpcResult; import org.apache.dubbo.rpc.protocol.AbstractInvoker; import org.apache.dubbo.rpc.support.RpcUtils; @@ -99,7 +100,7 @@ protected Result doInvoke(final Invocation invocation) throws Throwable { // register resultCallback, sometimes we need the asyn result being processed by the filter chain. result = new AsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false); } else { - result = new RpcResult(); + result = new SimpleAsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false); } return result; } else { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java index 19b22784838..4547b85f16f 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/FutureFilter.java @@ -20,21 +20,16 @@ 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.remoting.exchange.ResponseCallback; -import org.apache.dubbo.remoting.exchange.ResponseFuture; import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.PostProcessFilter; import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.StaticContext; -import org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.concurrent.Future; /** * EventFilter @@ -57,7 +52,7 @@ public Result postProcessResult(Result result, Invoker invoker, Invocation in if (result instanceof AsyncRpcResult) { AsyncRpcResult asyncResult = (AsyncRpcResult) result; asyncResult.thenApplyWithContext(r -> { - asyncCallback(invoker, invocation); + asyncCallback(invoker, invocation, r); return r; }); return asyncResult; @@ -75,35 +70,11 @@ private void syncCallback(final Invoker invoker, final Invocation invocation, } } - private void asyncCallback(final Invoker invoker, final Invocation invocation) { - Future f = RpcContext.getContext().getFuture(); - if (f instanceof FutureAdapter) { - ResponseFuture future = ((FutureAdapter) f).getFuture(); - future.setCallback(new ResponseCallback() { - @Override - public void done(Object rpcResult) { - if (rpcResult == null) { - logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName())); - return; - } - ///must be rpcResult - if (!(rpcResult instanceof Result)) { - logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName())); - return; - } - Result result = (Result) rpcResult; - if (result.hasException()) { - fireThrowCallback(invoker, invocation, result.getException()); - } else { - fireReturnCallback(invoker, invocation, result.getValue()); - } - } - - @Override - public void caught(Throwable exception) { - fireThrowCallback(invoker, invocation, exception); - } - }); + private void asyncCallback(final Invoker invoker, final Invocation invocation, Result result) { + if (result.hasException()) { + fireThrowCallback(invoker, invocation, result.getException()); + } else { + fireReturnCallback(invoker, invocation, result.getValue()); } } From f21fc21d6b6f26b336aeaf89ff9395b8107983b0 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 19 Jun 2018 16:13:02 +0800 Subject: [PATCH 36/39] fix UT error --- .../dubbo/rpc/protocol/dubbo/ImplicitCallBackTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ImplicitCallBackTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ImplicitCallBackTest.java index ca2ecc568da..773e72f1ead 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ImplicitCallBackTest.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ImplicitCallBackTest.java @@ -25,9 +25,8 @@ import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.StaticContext; import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils; - -import org.junit.Assert; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -37,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -272,7 +272,7 @@ public void test_Async_Future_Multi() throws Exception { } @Test(expected = RuntimeException.class) - public void test_Async_Future_Ex() throws Exception { + public void test_Async_Future_Ex() throws Throwable { try { initOrResetUrl(true); destroyService(); @@ -285,6 +285,8 @@ public void test_Async_Future_Ex() throws Exception { Future pFuture = RpcContext.getContext().getFuture(); ret = pFuture.get(1000 * 1000, TimeUnit.MICROSECONDS); Assert.assertEquals(requestId, ret.getId()); + } catch (ExecutionException e) { + throw e.getCause(); } finally { destroyService(); } From 2671a04978e5ad7bdc18c62a5976016e58adb333 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 19 Jun 2018 16:53:51 +0800 Subject: [PATCH 37/39] resolve compile problem after merge master --- .../main/java/com/alibaba/dubbo/rpc/Result.java | 15 +++++++++++++++ .../main/java/org/apache/dubbo/rpc/Result.java | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Result.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Result.java index 28ca666ba04..a661b2b6b5b 100644 --- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Result.java +++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Result.java @@ -63,6 +63,16 @@ public Map getAttachments() { return delegate.getAttachments(); } + @Override + public void addAttachments(Map map) { + delegate.addAttachments(map); + } + + @Override + public void setAttachments(Map map) { + delegate.setAttachments(map); + } + @Override public String getAttachment(String key) { return delegate.getAttachment(key); @@ -72,5 +82,10 @@ public String getAttachment(String key) { public String getAttachment(String key, String defaultValue) { return delegate.getAttachment(key, defaultValue); } + + @Override + public void setAttachment(String key, String value) { + delegate.setAttachment(key, value); + } } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java index a5bb4da9847..58a258241ff 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Result.java @@ -86,14 +86,14 @@ public interface Result extends Serializable { * * @param map */ - public void addAttachments(Map map); + void addAttachments(Map map); /** * Replace the existing attachments with the specified param. * * @param map */ - public void setAttachments(Map map); + void setAttachments(Map map); /** * get attachment by key. From 4977d6c06b260d212dc1d5a6308de0f8c5418efa Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Sat, 30 Jun 2018 17:47:38 +0800 Subject: [PATCH 38/39] Fix bug when use startAsync(). --- .../java/org/apache/dubbo/rpc/AsyncContext.java | 4 +--- .../org/apache/dubbo/rpc/AsyncContextImpl.java | 15 +++++---------- .../java/org/apache/dubbo/rpc/RpcContext.java | 4 +--- .../dubbo/rpc/proxy/AbstractProxyInvoker.java | 10 ++++++++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java index 0f5713d665b..388df719640 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java @@ -29,8 +29,6 @@ public interface AsyncContext { CompletableFuture getInternalFuture(); - void addListener(Runnable run); - /** * write value and complete the async context. * @@ -49,7 +47,7 @@ public interface AsyncContext { boolean stop(); /** - * change the context state to stop + * change the context state to start */ void start(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java index a68ff9abf62..9e4ddaf9ee6 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java @@ -26,6 +26,7 @@ public class AsyncContextImpl implements AsyncContext { private static final Logger logger = LoggerFactory.getLogger(AsyncContextImpl.class); private final AtomicBoolean started = new AtomicBoolean(false); + private final AtomicBoolean stoped = new AtomicBoolean(false); private CompletableFuture future; @@ -41,20 +42,14 @@ public AsyncContextImpl(CompletableFuture future) { this.storedServerContext = RpcContext.getServerContext(); } - @Override - public void addListener(Runnable run) { - - } - @Override public void write(Object value) { - if (stop()) { + if (isAsyncStarted() && stop()) { if (value instanceof Throwable) { - // TODO check exception type like ExceptionFilter do. Throwable bizExe = (Throwable) value; - future.complete(new RpcResult(bizExe)); + future.completeExceptionally(bizExe); } else { - future.complete(new RpcResult(value)); + future.complete(value); } } else { throw new IllegalStateException("The async response has probably been wrote back by another thread, or the asyncContext has been closed."); @@ -68,7 +63,7 @@ public boolean isAsyncStarted() { @Override public boolean stop() { - return started.compareAndSet(true, false); + return stoped.compareAndSet(false, true); } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index 598b57d3f44..f448650bc0f 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -719,9 +719,7 @@ public boolean isAsyncStarted() { } public boolean stopAsync() { - boolean stoped = asyncContext.stop(); - asyncContext = null; - return stoped; + return asyncContext.stop(); } public void setAsyncContext(AsyncContext asyncContext) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java index b208325d192..b275fa1d0d4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -17,6 +17,8 @@ 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.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -33,6 +35,7 @@ * InvokerWrapper */ public abstract class AbstractProxyInvoker implements Invoker { + Logger logger = LoggerFactory.getLogger(AbstractProxyInvoker.class); private final T proxy; @@ -77,18 +80,21 @@ public void destroy() { // TODO Unified to AsyncResult? @Override public Result invoke(Invocation invocation) throws RpcException { + RpcContext rpcContext = RpcContext.getContext(); try { - RpcContext rpcContext = RpcContext.getContext(); Object obj = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()); if (RpcUtils.isFutureReturnType(invocation)) { return new AsyncRpcResult((CompletableFuture) obj); - } else if (RpcContext.getContext().isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. + } else if (rpcContext.isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. return new AsyncRpcResult(rpcContext.getAsyncContext().getInternalFuture()); } else { return new RpcResult(obj); } } catch (InvocationTargetException e) { // TODO async throw exception before async thread write back, should stop asyncContext + if (rpcContext.isAsyncStarted() && !rpcContext.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()); } catch (Throwable e) { throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e); From 75b6f5553a99a1976bd2d1ad1279e9aa628b2b61 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Wed, 4 Jul 2018 20:23:18 +0800 Subject: [PATCH 39/39] Fix async UT --- .../src/test/java/org/apache/dubbo/rpc/RpcContextTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java index d298824b16e..7908975aec2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java @@ -142,7 +142,7 @@ public void testAsync() { Assert.assertTrue(future.isDone()); rpcContext.stopAsync(); - Assert.assertFalse(rpcContext.isAsyncStarted()); + Assert.assertTrue(rpcContext.isAsyncStarted()); } }