小弟一直苦思 consumer 与provider 究竟是怎么通讯的呢,与是从网上找了一篇,以为写得很靠谱。本身就算总结,也未必有这个好,因此记录下来!!java
消费者调用流程涉及到消费者端和生产者端的交互,因此将分为三个部分来说解,分别是
-消费者发起调用请求
-生产者响应调用请求
-消费者获取调用结果api
消费者发起调用请求app
以前文章中讲过消费者初始化时最后返回的是一个InvokerInvocationHandler
的代理对象,根据动态代理的原理,DUBBO接口的方法调用都会由invoke
方法代理,咱们来看一下其实现负载均衡
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]); } return invoker.invoke(new RpcInvocation(method, args)).recreate(); }
正常状况下的方法调用会走invoker.invoke(new RpcInvocation(method, args)).recreate()
这个分支,首先来看new RpcInvocation(method, args)
dom
public RpcInvocation(Method method, Object[] arguments) { this(method.getName(), method.getParameterTypes(), arguments, null, null); } public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments, Invoker<?> invoker) { this.methodName = methodName; this.parameterTypes = parameterTypes == null ? new Class<?>[0] : parameterTypes; this.arguments = arguments == null ? new Object[0] : arguments; this.attachments = attachments == null ? new HashMap<String, String>() : attachments; this.invoker = invoker; }
很是简单的一个初始化赋值操做,就不作过多讲解了,接着回头看invoker.invoke(new RpcInvocation(method, args))
方法,这里的invoker
以前也说过了,是一个经过SPI机制生成的对象,以默认设置的参数failover
为例,这里的invoker
就是一个MockClusterInvoker
对象中包含了一个FailoverClusterInvoker
对象引用的相似链式的对象,那么咱们来详细看看MockClusterInvoker
的invoke
方法异步
public Result invoke(Invocation invocation) throws RpcException { Result result = null; //获取mock属性的值,没有配置,默认false String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim(); if (value.length() == 0 || value.equalsIgnoreCase("false")){ //no mock result = this.invoker.invoke(invocation); } else if (value.startsWith("force")) { if (logger.isWarnEnabled()) { logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl()); } //force:direct mock result = doMockInvoke(invocation, null); } else { //fail-mock try { result = this.invoker.invoke(invocation); }catch (RpcException e) { if (e.isBiz()) { throw e; } else { if (logger.isWarnEnabled()) { logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e); } result = doMockInvoke(invocation, e); } } } return result; }
当没有配置mock
值时,value
值获得的是默认值false
,会去执行result = this.invoker.invoke(invocation)
,this.invoker
刚才提到过了是一个FailoverClusterInvoker
类型的对象,但该对象并无实现invoke
方法,实际上该方法是继承自父类AbstractClusterInvoker
的,来看一下ide
public Result invoke(final Invocation invocation) throws RpcException { checkWheatherDestoried(); LoadBalance loadbalance; List<Invoker<T>> invokers = list(invocation); if (invokers != null && invokers.size() > 0) { loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl() .getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE)); } else { loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE); } //异步操做默认添加invocation id RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); return doInvoke(invocation, invokers, loadbalance); }
这里的list(invocation)
方法根据invocation
中的参数来获取全部的invoker
列表,就不深刻讲了,接着来看loadbalance
对象的生成,loadbalance
对象根据SPI机制生成,具体实现由loadbalance
参数决定,也就是具体的负载均衡策略,DUBBO提供的实现有random
、roundrobin
、leastactive
、consistenthash
四种,其中没有根据服务端负载进行调节的策略。其中默认实现为random
,生成的loadbalance
就是一个RandomLoadBalance
的对象。本次只分析同步的接口调用方式,跳过RpcUtils.attachInvocationIdIfAsync
,接着看doInvoke(invocation, invokers, loadbalance)方法,该方法实如今FailoverClusterInvoker
中oop
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { List<Invoker<T>> copyinvokers = invokers; //检查invokers是否为空 checkInvokers(copyinvokers, invocation); //获取重试次数 int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; } // retry loop. RpcException le = null; // last exception. List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers. Set<String> providers = new HashSet<String>(len); for (int i = 0; i < len; i++) { //重试时,进行从新选择,避免重试时invoker列表已发生变化. //注意:若是列表发生了变化,那么invoked判断会失效,由于invoker示例已经改变 if (i > 0) { checkWheatherDestoried(); //得到InvokerWrapper的List copyinvokers = list(invocation); //从新检查一下 checkInvokers(copyinvokers, invocation); } Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked); invoked.add(invoker); RpcContext.getContext().setInvokers((List)invoked); try { Result result = invoker.invoke(invocation); if (le != null && logger.isWarnEnabled()) { logger.warn(""); } return result; } catch (RpcException e) { if (e.isBiz()) { // biz exception. throw e; } le = e; } catch (Throwable e) { le = new RpcException(e.getMessage(), e); } finally { providers.add(invoker.getUrl().getAddress()); } } throw new RpcException /** * 略去部分代码 */ }
这里select(loadbalance, invocation, copyinvokers, invoked)
方法根据传入的loadbalance
对象挑选出一个执行用的invoker
,里面调用链较深,在此不作详细分析。最终将经过invoker.invoke(invocation)
进行调用并返回一个Result
类型的对象,也就是最终的执行结果,这里的invoker
对象是InvokerWrapper
的实例,该实例引用了一个ListenerInvokerWrapper
的实例,接着又链式引用了AbstractInvoker
的实例,所以最终执行的invoke
方法在AbstractInvoker
中,来看一下ui
public Result invoke(Invocation inv) throws RpcException { if(destroyed) { throw new RpcException("略"); } RpcInvocation invocation = (RpcInvocation) inv; invocation.setInvoker(this); if (attachment != null && attachment.size() > 0) { invocation.addAttachmentsIfAbsent(attachment); } Map<String, String> context = RpcContext.getContext().getAttachments(); if (context != null) { invocation.addAttachmentsIfAbsent(context); } if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)){ invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString()); } //异步操做默认添加invocation id RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); try { return doInvoke(invocation); } catch (InvocationTargetException e) { // biz exception /** * 略去部分代码 */ } }
这里的关键方法是doInvoke(invocation)
,其实如今具体的Invoker
实现类中,这里咱们采用的是默认的dubbo协议,因此实现类为DubboInvoker
,来看看其doInvoke
方法this
@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 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) ; RpcContext.getContext().setFuture(new FutureAdapter<Object>(future)); return new RpcResult(); } else { RpcContext.getContext().setFuture(null); return (Result) currentClient.request(inv, timeout).get(); } /** * 略去部分代码 */ }
这里的isOneway
和isAsync
两个标志位分别区分单向调用(不在意调用结果)和异步调用,这里咱们分析同步调用的流程,这里的currentClient
是一个ReferenceCountExchangeClient
类型的对象
public ResponseFuture request(Object request) throws RemotingException { return client.request(request); }
这里的client
是一个HeaderExchangeClient
类型的对象,
public ResponseFuture request(Object request) throws RemotingException { return channel.request(request); }
这里的channel
是一个HeaderExchangeChannel
类型的对象,继续跟进去
public ResponseFuture request(Object request) throws RemotingException { return request(request, channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); } 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("2.0.0"); 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; }
这里的request
方法本身又进行了一次内部调用,能够看到具体实现时建立了一个DefaultFuture
对象而且经过channel.send(req)
方法发送请求到生产者端,这里不作具体深刻了。接着咱们跳回DubboInvoker
类doInvoke
方法中的currentClient.request(inv, timeout).get()
,这里是否是和jdk中future的用法很像,事实上这里也确实是经过get
方法的调用将线程阻塞在这里等待结果,从而将异步调用转化为同步。为了证明这个想法,咱们来看看DefaultFuture
的get
方法
public Object get() throws RemotingException { return get(timeout); } public Object get(int timeout) throws RemotingException { if (timeout <= 0) { timeout = Constants.DEFAULT_TIMEOUT; } if (! isDone()) { long start = System.currentTimeMillis(); lock.lock(); try { while (! isDone()) { done.await(timeout, TimeUnit.MILLISECONDS); if (isDone() || System.currentTimeMillis() - start > timeout) { break; } } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } if (! isDone()) { throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false)); } } return returnFromResponse(); }
从done.await(timeout, TimeUnit.MILLISECONDS)
能够看到这里不只是等待isDone()
这个状态位,同时还有超时时间的限制。isDone()
判断的是什么,来看一下
public boolean isDone() { return response != null; }
判断response
对象是否为空,那么后面的流程其实不难猜,生产者处理完结果会来填充response
。
生产者响应调用请求
生产者开启了端口监听,消息的解码由Netty处理,解码后交由NettyHandler
的messageReceived
方法进行业务处理,来看一下
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler); try { handler.received(channel, e.getMessage()); } finally { NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); } }
先来看一下NettyChannel.getOrAddChannel
static NettyChannel getOrAddChannel(org.jboss.netty.channel.Channel ch, URL url, ChannelHandler handler) { if (ch == null) { return null; } NettyChannel ret = channelMap.get(ch); if (ret == null) { NettyChannel nc = new NettyChannel(ch, url, handler); if (ch.isConnected()) { ret = channelMap.putIfAbsent(ch, nc); } if (ret == null) { ret = nc; } } return ret; }
主要是从channelMap
中获取对应的NettyChannel
,接着回到NettyHandler
的messageReceived
方法来看handler.received(channel, e.getMessage())
,这里的handler
是一个NettyServer
的实例,但它自己没有实现received
方法,该方法要追溯到它的父类的父类的父类(真的就是这么长的继承关系。。。)AbstractPeer
中,来看一下
public void received(Channel ch, Object msg) throws RemotingException { if (closed) { return; } handler.received(ch, msg); }
这里的handler
是MultiMessageHandler
对象的实例,来看一下其received
方法的实现
@Override public void received(Channel channel, Object message) throws RemotingException { if (message instanceof MultiMessage) { MultiMessage list = (MultiMessage)message; for(Object obj : list) { handler.received(channel, obj); } } else { handler.received(channel, message); } }
这里的handler
又是HeartbeatHandler
类的实例
public void received(Channel channel, Object message) throws RemotingException { setReadTimestamp(channel); if (isHeartbeatRequest(message)) { Request req = (Request) message; if (req.isTwoWay()) { Response res = new Response(req.getId(), req.getVersion()); res.setEvent(Response.HEARTBEAT_EVENT); channel.send(res); if (logger.isInfoEnabled()) { int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0); if(logger.isDebugEnabled()) { logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress() + ", cause: The channel has no data-transmission exceeds a heartbeat period" + (heartbeat > 0 ? ": " + heartbeat + "ms" : "")); } } } return; } if (isHeartbeatResponse(message)) { if (logger.isDebugEnabled()) { logger.debug( new StringBuilder(32) .append("Receive heartbeat response in thread ") .append(Thread.currentThread().getName()) .toString()); } return; } handler.received(channel, message); }
由于不是心跳类的消息,因此执行handler.received(channel, message)
继续这个调用链,这里的handler
是AllChannelHandler
类型的
public void received(Channel channel, Object message) throws RemotingException { ExecutorService cexecutor = getExecutorService(); try { cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message)); } catch (Throwable t) { throw new ExecutionException(message, channel, getClass() + " error when process received event .", t); } }
这里终于结束了调用链,转而启动了一个线程池来执行任务,那咱们来看看具体的任务线程ChannelEventRunnable
中到底须要执行什么任务
public void run() { switch (state) { case CONNECTED: try{ handler.connected(channel); }catch (Exception e) { logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); } break; case DISCONNECTED: try{ handler.disconnected(channel); }catch (Exception e) { logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e); } break; case SENT: try{ handler.sent(channel,message); }catch (Exception e) { logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel + ", message is "+ message,e); } break; case RECEIVED: try{ handler.received(channel, message); }catch (Exception e) { logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel + ", message is "+ message,e); } break; case CAUGHT: try{ handler.caught(channel, exception); }catch (Exception e) { logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is "+ channel + ", message is: " + message + ", exception is " + exception,e); } break; default: logger.warn("unknown state: " + state + ", message is " + message); } }
这里传入的是RECEIVED
状态,执行对应分支又是调用handler.received(channel, message)
,好吧继续。。。
这里的handler
是DecodeHandler
的实例,继续跟下去
public void received(Channel channel, Object message) throws RemotingException { if (message instanceof Decodeable) { decode(message); } if (message instanceof Request) { decode(((Request)message).getData()); } if (message instanceof Response) { decode( ((Response)message).getResult()); } handler.received(channel, message); }
调用链还在继续,此次的handler
是HeaderExchangeHandler
类型
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()) { Response response = handleRequest(exchangeChannel, request); channel.send(response); } 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); } }
正常同步请求会开始执行handleRequest(exchangeChannel, request)
处理请求,并经过channel.send(response)
回复结果,来重点看一下handleRequest
方法
Response 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); return res; } // find handler by message class. Object msg = req.getData(); try { // handle data. Object result = handler.reply(channel, msg); res.setStatus(Response.OK); res.setResult(result); } catch (Throwable e) { res.setStatus(Response.SERVICE_ERROR); res.setErrorMessage(StringUtils.toString(e)); } return res; }
能够看出正常请求将由handler.reply(channel, msg)
处理,这里的handler
是DubboProtocol
中的一个ExchangeHandlerAdapter
实现,其reply
方法以下
public Object reply(ExchangeChannel channel, Object message) throws RemotingException { if (message instanceof Invocation) { Invocation inv = (Invocation) message; //经过方法名获取Invoker Invoker<?> invoker = getInvoker(channel, inv); //若是是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.indexOf(",") == -1){ 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.getContext().setRemoteAddress(channel.getRemoteAddress()); return invoker.invoke(inv); } throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress()); }
这里一共作了两件事,先经过getInvoker(channel, inv)
获取具体的invoker
,再经过invoker.invoke(inv)
执行获取结果,先来看一下getInvoker(channel, inv)
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); //若是是客户端的回调服务. 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(); }
这里又看到了熟悉的exporterMap
,以前讲生产者初始化的时候就说过这个map中放入了封装过的Invoker
对象exporter
,如今又把它取了出了并经过getInvoker()
方法得到封装在其中的Invoker
对象。
接着来看invoker.invoke(inv)
方法,其实现首先在InvokerWrapper
类中
public Result invoke(Invocation invocation) throws RpcException { return invoker.invoke(invocation); }
而后会调用到AbstractProxyInvoker
中的invoke
方法
public Result invoke(Invocation invocation) throws RpcException { try { return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments())); } catch (InvocationTargetException 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); } }
这里doInvoke
方法的实如今JavassistProxyFactory
中getInvoker
方法中
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // TODO Wrapper类不能正确处理带$的类名 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }
这里根据传入的 proxy
对象的类信息建立对它的包装对象Wrapper
并调用其invokeMethod
方法,经过传入的参数来调用proxy
对象的对应方法,返回调用结果,也就是执行具体的业务。
完成handleRequest(exchangeChannel, request)
方法的解析后,回到HeaderExchangeHandler
类中接着来看一下channel.send(response)
,这里的channel
传入的是NettyChannel
类型的对象,send
方法的实如今其父类的父类AbstractPeer
中,来看一下
public void send(Object message) throws RemotingException { send(message, url.getParameter(Constants.SENT_KEY, false)); }
其具体实现又在NettyChannel
中
public void send(Object message, boolean sent) throws RemotingException { super.send(message, sent); boolean success = true; int timeout = 0; try { ChannelFuture future = channel.write(message); if (sent) { timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); success = future.await(timeout); } Throwable cause = future.getCause(); if (cause != null) { throw cause; } } catch (Throwable e) { throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e); } if(! success) { throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + "in timeout(" + timeout + "ms) limit"); } }
能够看到业务处理结果最后经过ChannelFuture
对象进行了发送,到今生产者端的任务就完成了。
消费者获取调用结果
这里消费者端经过NETTY从生产者端获取数据的流程和以前的一模一样,调用链直到HeaderExchangeHandler
以前都是同样的,咱们先来回顾一下HeaderExchangeHandler
的received
方法
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()) { Response response = handleRequest(exchangeChannel, request); channel.send(response); } 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); } }
以前走的是Request分支,此次由于是响应消息走的是Response分支,那么来看一下handleResponse(channel, (Response) message)
的具体实现
static void handleResponse(Channel channel, Response response) throws RemotingException { if (response != null && !response.isHeartbeat()) { DefaultFuture.received(channel, response); } }
继续跟进去看received
方法
public static void received(Channel channel, Response response) { try { DefaultFuture future = FUTURES.remove(response.getId()); if (future != null) { future.doReceived(response); } else { logger.warn("The timeout response finally returned at " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) + ", response " + response + (channel == null ? "" : ", channel: " + channel.getLocalAddress() + " -> " + channel.getRemoteAddress())); } } finally { CHANNELS.remove(response.getId()); } }
继续看doReceived
干了什么
private void doReceived(Response res) { lock.lock(); try { response = res; if (done != null) { done.signal(); } } finally { lock.unlock(); } if (callback != null) { invokeCallback(callback); } }
看到这里把执行结果赋值给response
,正好应证了咱们以前的猜测,消费者的同步阻塞也就能够继续执行下去了,这也算是很是经典的异步转同步的实现方案了吧。
本文把消费者端和生产者端交互的大概流程进行了讲解,流程主要分为三个部分,分别是:消费者发起调用请求、生产者响应调用请求和消费者获取调用结果,归纳一下就是消费者经过生成的代理对象调用invoke
方法经过Netty的通道去请求生产者的exporter
进行执行,而且经过future
的方式将异步的交互转为了同步响应。