Dubbo源码之通过Customer访问Provider的服务的源码解析(Java版)

1.查看源码

    	// 当前应用配置
    	ApplicationConfig application = new ApplicationConfig();
    	application.setName("hello-world-app-customer");
    	 
    	// 连接注册中心配置
    	RegistryConfig registry = new RegistryConfig();
    	registry.setAddress("zookeeper://192.168.133.129:2181");
    	 
    	// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
    	 
    	// 引用远程服务
    	ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
    	reference.setApplication(application);
    	reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
    	reference.setInterface(DemoService.class);
    	reference.setVersion("1.0.0");
    	 
    	// 和本地bean一样使用xxxService
    	DemoService demoService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用
    	String say = demoService.say("World");
    	System.out.println(say);

1.通过前面的Provider的源码发现其中的ApplicationConfig和RegistryConfig以及ReferenceConfig只是前期的配置工作

2.通过debug发现reference.get()这个方法的调用,返回的DemoService的结果是一个代理对象,而这个代理对象实际上是使用jdk的接口代理实现的,所以它的实现方法为Invoke,通过查看控制台打印的信息发现当前的get方法实际上会连接Zookeeper(检查其连通性)

3.所以档期那的demoService.say实际上是使用代理方式实现的,其类型为org.apache.dubbo.common.bytecode.proxy0@226642a5

4.通过debug发现当前的proxy代理类中具有一个handler其实际类型为InvokerInvocationHandler类型

2.查看InvokerInvocationHandler中的invoke方法

    @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) {//判断当前方法的类型是否为object类型
            return method.invoke(invoker, args);
        }
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();//判断当前调用的方法是否为toString方法
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();//判断当前调用的方法名是否为hashCode方法
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);//判断当前调用的方法名称是否为equals方法
        }
		//调用代理类的invoke方法,通过debug发现实际上调用的是MockClusterInvoker<T>中的invoke方法
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

2.1 查看MockClusterInvoker类的invoke方法

@Override
  @Override
    public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;//定义返回的结果

        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();//
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            //no mock
            result = this.invoker.invoke(invocation);//发现实际上调用的是这个方法:FailoverClusterInvoker类中的invoke方法,
        } else if (value.startsWith("force")) {
            if (logger.isWarnEnabled()) {
                logger.warn("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;
                }

                if (logger.isWarnEnabled()) {
                    logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                }
                result = doMockInvoke(invocation, e);
            }
        }
        return result;
    }

通过debug发现当前实际上调用的是FailoverClusterInvoker类中的invoke方法,但是当前类FailoverClusterInvoker没有这个方法只有一个doInvoke方法,所以断定当前的invoke方法实际上是抽象父类的方法实际上还是调用doInvoke方法

2.2 查看FailoverClusterInvoker的doInvoke方法

  @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyInvokers = invokers;
        checkInvokers(copyInvokers, invocation);//检查调用的方法是否存在
        String methodName = RpcUtils.getMethodName(invocation);//桶过工具获取调用方法的方法名
        int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;//获取方法名的长度这里为say所以长度都为3
        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++) {//循环3次
            //Reselect before retry to avoid a change of candidate `invokers`.
            //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
            if (i > 0) {//当i>0的是否做的事情
                checkWhetherDestroyed();//检查当前是否销毁
                copyInvokers = list(invocation);
                // check again
                checkInvokers(copyInvokers, invocation);//检查需要调用的方法是否存在
            }
            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);//通过查询获取实际需要调用的方法或者访问的url(使用dubbo协议的)dubbo://192.168.133.1:20880/com.hy.dubbo.api.DemoService
            invoked.add(invoker);//然后向需要调用的invokes集合中添加已经调用的方法
            RpcContext.getContext().setInvokers((List) invoked);
            try {
                Result result = invoker.invoke(invocation);//实际调用方法并获取返回值结果
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + methodName
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers
                            + " (" + providers.size() + "/" + copyInvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                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(le.getCode(), "Failed to invoke the method "
                + methodName + " in the service " + getInterface().getName()
                + ". Tried " + len + " times of the providers " + providers
                + " (" + providers.size() + "/" + copyInvokers.size()
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + le.getMessage(), le.getCause() != null ? le.getCause() : le);
    }

通过debug发现当前的invoker.invoke(invocation);中的invokerde 实际类型为ProtocolFilterWrapper中的静态类CallbackRegistrationInvoker中的invoke方法

2.3 查看ProtocolFilterWrapper.CallbackRegistrationInvoker中的invoke方法

  @Override
        public Result invoke(Invocation invocation) throws RpcException {
            Result asyncResult = filterInvoker.invoke(invocation);//发现实际上调用的是ListenerInvokerWrapper中的invoke方法

            asyncResult = asyncResult.whenCompleteWithContext((r, t) -> {
                for (int i = filters.size() - 1; i >= 0; i--) {
                    Filter filter = filters.get(i);
                    // onResponse callback
                    if (filter instanceof ListenableFilter) {
                        Filter.Listener listener = ((ListenableFilter) filter).listener();
                        if (listener != null) {
                            if (t == null) {
                                listener.onResponse(r, filterInvoker, invocation);
                            } else {
                                listener.onError(t, filterInvoker, invocation);
                            }
                        }
                    } else {
                        filter.onResponse(r, filterInvoker, invocation);
                    }
                }
            });
            return asyncResult;
        }

通过源码发现当前实际上调用的是ListenerInvokerWrapper中的invoke方法

2.4 查看ListenerInvokerWrapper中的invoke方法

@Override
    public Result invoke(Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);//发现又是一个代理类,通过debug返现调用的是DubboInvoker
    }

通过debug发现实际上调用的DubboInvoker类的invoke方法

2.5 查看DubboInvoker类的invoke方法

 @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;//创建RPC执行器
        final String methodName = RpcUtils.getMethodName(invocation);//通过RpcUtils获取当前的调用的方法名
        inv.setAttachment(PATH_KEY, getUrl().getPath());//设置当前调用的方式
        inv.setAttachment(VERSION_KEY, version);//设置当前的版本

        ExchangeClient currentClient;//创建交换客户端
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
            int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);//获取执行方法的超时时间默认为1000ms
            if (isOneway) {//为false
                boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                currentClient.send(inv, isSent);
                return AsyncRpcResult.newDefaultAsyncResult(invocation);
            } else {
                AsyncRpcResult asyncRpcResult = new AsyncRpcResult(inv);//创建一个异步的Rpc结果
                CompletableFuture<Object> responseFuture = currentClient.request(inv, timeout);//通过交换客户端进行发送请求,并获得响应的记过
                asyncRpcResult.subscribeTo(responseFuture);
                // save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
                FutureContext.getContext().setCompatibleFuture(responseFuture);
                return asyncRpcResult;
            }
        } 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);
        }
    }

通过debug发现当前的DubboInvoker类中的Invoker方法实际上就是创建一个交换客户端,通过交换客户端发送请求并获得结果currentClient.request(inv, timeout);

2.6 查看HeaderExchangeClient中的request方法

    @Override
    public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
        return channel.request(request, timeout);
    }

通过debug发现发现channel为HeaderExchangeChannel类型

2.7 查看HeaderExchangeChannel中的request方法

@Override
    public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
        if (closed) {//判断当前的交换机是否关闭
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        }
        // create request.
        Request req = new Request();//开始创建一个请求
        req.setVersion(Version.getProtocolVersion());//设置版本信息
        req.setTwoWay(true);//设置是否为第二个方法
        req.setData(request);//设置请求的数据
        DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);//创建一个执行器
        try {
            channel.send(req);//开始发送请求
        } catch (RemotingException e) {
            future.cancel();//出现问题后就取消请求
            throw e;
        }
        return future;
    }

1.发现当前的HeaderExchangeChannel中的request方法会创建一个Request类封装请求,然后通过channel.send(req)发送请求,所以执行后返回的结果在DefaultFuture中

2.通过debug发现当前的channel的实际类型为NettyClient,但是其没有任何关于send方法,所以这个方法在于父类中

2.8 查看NettyClient的父类的AbstractClient中的send方法

@Override
    public void send(Object message, boolean sent) throws RemotingException {
        if (needReconnect && !isConnected()) {
            connect();
        }
        Channel channel = getChannel();//获取发送信息的管道
        //TODO Can the value returned by getChannel() be null? need improvement.
        if (channel == null || !channel.isConnected()) {
            throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
        }
        channel.send(message, sent);//发送信息
    }

通过源码发现message:Request [id=1, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=say, parameterTypes=[class java.lang.String], arguments=[World], attachments={path=com.hy.dubbo.api.DemoService, interface=com.hy.dubbo.api.DemoService, version=1.0.0}]]

所以当前的message中具有当前所有请求的信息

channel的实际类型为NettyChannel

2.9 查看NettyChannel中的send方法

 @Override
    public void send(Object message, boolean sent) throws RemotingException {
        // 通道是否关闭
        super.send(message, sent);

        boolean success = true;//是否发送成功
        int timeout = 0;//定义超时时间
        try {
            ChannelFuture future = channel.writeAndFlush(message);//开始写和发送消息
            if (sent) {//判断是否已经发下哦那个
                // wait timeout ms
                timeout = getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);//获取超时时间
                success = future.await(timeout);//通过等待的方式判断当前的任何五是否执行成功
            }
            Throwable cause = future.cause();
            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");
        }
    }

1.通过源码发现当前的NettyChannel方法是调用一个可回调的类进行执行操作

2.debug发现当前的channel.writeAndFlush(message);中的channel实际上为NettySocketChannel

3.所以当前的Customer实际上就是通过Netty对服务提供者进行发送消息的请求,然后通过回调的方式返回调用的结果,这个具有超时时间

3.总结

1.当前的客户端获取的任何实例都是一个代理对象,给代理对象的操作都会调用invoke方法,所有的操作都统一在invoke方法中实现(这点和MyBatis的源码相似)

2.dubbo中的代理模式使用的太多了,可能会导致源码难以看懂

3.dubbo通过异步的方式使用Netty发送消息请求,并在1000ms内获取的返回结果,对于使用debug查看可能不是很友好,因为debug不止1秒的时间所以通常会导致结果为null,还有请求超时的异常

4.通过阅读源码发现当前的dubbo中使用了大量的代理java.util.concurrent.Future<V>这个类

以上纯属个人见解,如有问题请联系本人!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值