Dubbo-Hello world源码分析(5)

Dubbo-协议和序列化

Dubbo rpc调用远程方法就像调用本地方法一样!!方便的背后,肯定有很多技术的支持。

本文通过hello world简单跟踪一下源码,简单体验一下dubbo背后的技术。

1. hello world中远程调用源码分析
  1. 入口
     String hello = providerService.sayHello(next);

2.debug时F7进入com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler

package com.alibaba.dubbo.rpc.proxy;

import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcInvocation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//继承了InvocationHandler——》动态代理
public class InvokerInvocationHandler implements InvocationHandler {
    private final Invoker<?> invoker;   //jdk动态代理接口,这个Invoker就是接口

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();   //被代理方法名
        Class<?>[] parameterTypes = method.getParameterTypes();   //方法参数列表
        //如果代理的是Object对象
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this.invoker, args);
        //如果代理方法是toString或hashCode或equals
        } else if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return this.invoker.toString();
        } else if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return this.invoker.hashCode();
        } else {
            return "equals".equals(methodName) && parameterTypes.length == 1 ? this.invoker.equals(args[0]) : this.invoker.invoke(new RpcInvocation(method, args)).recreate();   //在这里继续F7
        }
    }
}

//被代理接口
public interface Invoker<T> extends Node {
    Class<T> getInterface();

    Result invoke(Invocation var1) throws RpcException;
}

//Result
package com.alibaba.dubbo.rpc;
import java.util.Map;
public interface Result {
    Object getValue();

    Throwable getException();

    boolean hasException();

    Object recreate() throws Throwable;

    /** @deprecated */
    @Deprecated
    Object getResult();

    Map<String, String> getAttachments();

    String getAttachment(String var1);

    String getAttachment(String var1, String var2);
}

//Invocation
package com.alibaba.dubbo.rpc;
import java.util.Map;
public interface Invocation {
    String getMethodName();

    Class<?>[] getParameterTypes();

    Object[] getArguments();

    Map<String, String> getAttachments();

    String getAttachment(String var1);

    String getAttachment(String var1, String var2);

    Invoker<?> getInvoker();
}

//RpcInvocation
public class RpcInvocation implements Invocation, Serializable {...}
  1. 继续F7进入com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker
.
.
.
//该类中又有一个invoker
private final Invoker<T> invoker;
public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;
        String value = this.directory.getUrl().getMethodParameter(invocation.getMethodName(), "mock", Boolean.FALSE.toString()).trim();
        //这一大坨先不管
        if (value.length() != 0 && !value.equalsIgnoreCase("false")) {
            if (value.startsWith("force")) {
                if (logger.isWarnEnabled()) {
                    logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + this.directory.getUrl());
                }

                result = this.doMockInvoke(invocation, (RpcException)null);
            } else {
                try {
                    result = this.invoker.invoke(invocation);
                } catch (RpcException var5) {
                    if (var5.isBiz()) {
                        throw var5;
                    }

                    if (logger.isWarnEnabled()) {
                        logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + this.directory.getUrl(), var5);
                    }

                    result = this.doMockInvoke(invocation, var5);
                }
            }
        //调试时,进入这个,又是另一个Invoker
        } else {
            result = this.invoker.invoke(invocation);
        }

        return result;
    }
.
.
.
  1. 另一个Invoker, com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker
    public Result invoke(Invocation invocation) throws RpcException {
        this.checkWhetherDestroyed();
        LoadBalance loadbalance = null;
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        //这个先不管,没进入
        if (contextAttachments != null && contextAttachments.size() != 0) {
            ((RpcInvocation)invocation).addAttachments(contextAttachments);
        }

        List<Invoker<T>> invokers = this.list(invocation);
        //这里应该是选择负载均衡策略,进入了...
        if (invokers != null && !invokers.isEmpty()) {
            loadbalance = (LoadBalance)ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(((Invoker)invokers.get(0)).getUrl().getMethodParameter(RpcUtils.getMethodName(invocation), "loadbalance", "random"));
        }

        RpcUtils.attachInvocationIdIfAsync(this.getUrl(), invocation);
        //进入这个,前面不懂,先不要在意
        return this.doInvoke(invocation, invokers, loadbalance);
    }
  1. 继续F7进入com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.dubbo.rpc.cluster.support;

import com.alibaba.dubbo.common.Version;
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.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.cluster.Directory;
import com.alibaba.dubbo.rpc.cluster.LoadBalance;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
    private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);

    public FailoverClusterInvoker(Directory<T> directory) {
        super(directory);
    }

    //从这里看
    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyinvokers = invokers;
        this.checkInvokers(invokers, invocation);
        int len = this.getUrl().getMethodParameter(invocation.getMethodName(), "retries", 2) + 1;
        if (len <= 0) {
            len = 1;
        }

        RpcException le = null;
        List<Invoker<T>> invoked = new ArrayList(invokers.size());
        Set<String> providers = new HashSet(len);

        for(int i = 0; i < len; ++i) {
            if (i > 0) {
                this.checkWhetherDestroyed();
                copyinvokers = this.list(invocation);
                this.checkInvokers(copyinvokers, invocation);
            }

            Invoker<T> invoker = this.select(loadbalance, invocation, copyinvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers(invoked);

            try {
                //这个是重点了,因为返回了结果, 在这里继续F7
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + invocation.getMethodName() + " in the service " + this.getInterface().getName() + " was successful by the provider " + invoker.getUrl().getAddress() + ", but there have been failed providers " + providers + " (" + providers.size() + "/" + copyinvokers.size() + ") from the registry " + this.directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + le.getMessage(), le);
                }

                Result var12 = result;
                return var12;
            } catch (RpcException var17) {
                if (var17.isBiz()) {
                    throw var17;
                }

                le = var17;
            } catch (Throwable var18) {
                le = new RpcException(var18.getMessage(), var18);
            } finally {
                providers.add(invoker.getUrl().getAddress());
            }
        }

        throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method " + invocation.getMethodName() + " in the service " + this.getInterface().getName() + ". Tried " + len + " times of the providers " + providers + " (" + providers.size() + "/" + copyinvokers.size() + ") from the registry " + this.directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + (le != null ? le.getMessage() : ""), (Throwable)(le != null && le.getCause() != null ? le.getCause() : le));
    }
}

  1. 继续F7,最终进入 com.alibaba.dubbo.rpc.filter.ProtocolFilterWrapper
package com.alibaba.dubbo.rpc.filter;

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;
import com.alibaba.dubbo.rpc.RpcResult;

@Activate(
    group = {"consumer"},
    order = -10000
)
public class ConsumerContextFilter implements Filter {
    public ConsumerContextFilter() {
    }

    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);
        }

        RpcResult var4;
        try {
            //这里就是远程调用,继续F7
            RpcResult result = (RpcResult)invoker.invoke(invocation);
            RpcContext.getServerContext().setAttachments(result.getAttachments());
            var4 = result;
        } finally {
            RpcContext.getContext().clearAttachments();
        }

        return var4;
    }
}
  1. 又F7
   protected Result doInvoke(Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation)invocation;
        String methodName = RpcUtils.getMethodName(invocation);
        inv.setAttachment("path", this.getUrl().getPath());
        inv.setAttachment("version", this.version);
        ExchangeClient currentClient;
        if (this.clients.length == 1) {
            currentClient = this.clients[0];
        } else {
            currentClient = this.clients[this.index.getAndIncrement() % this.clients.length];
        }

        try {
            boolean isAsync = RpcUtils.isAsync(this.getUrl(), invocation);
            boolean isOneway = RpcUtils.isOneway(this.getUrl(), invocation);
            int timeout = this.getUrl().getMethodParameter(methodName, "timeout", 1000);
            if (isOneway) {
                boolean isSent = this.getUrl().getMethodParameter(methodName, "sent", false);
                currentClient.send(inv, isSent);
                RpcContext.getContext().setFuture((Future)null);
                return new RpcResult();
            } else if (isAsync) {
                ResponseFuture future = currentClient.request(inv, timeout);
                RpcContext.getContext().setFuture(new FutureAdapter(future));
                return new RpcResult();
            } else {
                RpcContext.getContext().setFuture((Future)null);
                //这就是最后调用了,继续F7
                return (Result)currentClient.request(inv, timeout).get();
            }
        } catch (TimeoutException var9) {
            throw new RpcException(2, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var9.getMessage(), var9);
        } catch (RemotingException var10) {
            throw new RpcException(1, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var10.getMessage(), var10);
        }
    }
  1. 继续多次F7, 进入com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel
//这里就是根了    
public ResponseFuture request(Object request, int timeout) throws RemotingException {
        if (this.closed) {
            throw new RemotingException(this.getLocalAddress(), (InetSocketAddress)null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        } else {
            Request req = new Request();
            req.setVersion(Version.getProtocolVersion());
            req.setTwoWay(true);
            req.setData(request);
            DefaultFuture future = new DefaultFuture(this.channel, req, timeout);

            try {
                this.channel.send(req);
                return future;
            } catch (RemotingException var6) {
                future.cancel();
                throw var6;
            }
        }
    }


//ResponseFuture
package com.alibaba.dubbo.remoting.exchange;

import com.alibaba.dubbo.remoting.RemotingException;

public interface ResponseFuture {
    Object get() throws RemotingException;

    Object get(int var1) throws RemotingException;

    void setCallback(ResponseCallback var1);

    boolean isDone();
}
2. 总结及思考
	1. 可以看到,虽然我们使用起来很简单,但dubbo框架确实封装了很多东西。这其中就是可以学习,参考的地方。
	2. 本文使用的是dubbo协议,如果换成别的协议呢?
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值