dubbo远程调用源码分析(一):客户端发送请求

dubbo远程调用的源码分析,分成了三篇文章地址分别如下:

dubbo远程调用源码分析(一):客户端发送请求

dubbo远程调用源码分析(二):服务端接收请求

dubbo远程调用源码分析(三):客户端接收反馈后的处理


本文分为三部分,分别是:

消费端注册部分

消费端动态代理部分

消费端事件处理器部分


消费端注册部分

在分析dubbo远程调用的时候,要从dubbo消费端(consumer)注册开始说起

dubbo的consumer在注册的时候,在配置文件中是用以下形式注册的:

<dubbo:reference id="sequenceService" interface="SequenceService"/>

在服务启动的时候,这个配置项会生成一个ReferenceBean的对象,当我们在代码中使用SequenceService时,实际上我们使用的是这个ReferenceBean对象调用getObject()方法之后返回的对象,这个对象就是SequenceService的代理对象。

先看一下ReferenceBean类的getObject()方法:

   public Object getObject() throws Exception {

        return get();

   }

get()方法在ReferenceBean的父类ReferenceConfig中:

   public synchronized T get() {

        if (destroyed) {  

            throw new IllegalStateException("Already destroyed!");

        }

        if (ref == null) {

            init();

        }

        return ref;

   }

返回的这个ref就是代理类,下面看一下用来初始化的init()方法:

   private void init() {

        if (initialized) {

            return;

        }

        initialized = true;

        if (interfaceName == null ||interfaceName.length() == 0) {

            throw new IllegalStateException("<dubbo:reference interface=\"\" />interface not allow null!");

        }

        // 获取消费者全局配置

        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 newIllegalStateException(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 = newFile(new File(System.getProperty("user.home")),"dubbo-resolve.properties");

                if (userResolveFile.exists()) {

                    resolveFile =userResolveFile.getAbsolutePath();

                }

            }

            if (resolveFile != null &&resolveFile.length() > 0) {

                Properties properties = newProperties();

                FileInputStream fis = null;

                try {

                    fis = newFileInputStream(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&& resolveFile.length() > 0) {

                    logger.warn("Usingdefault dubbo resolve file " + resolveFile + " replace " +interfaceName + "" + resolve + " to p2p invoke remoteservice.");

                } else {

                    logger.warn("Using-D" + interfaceName + "=" + resolve + " to p2p invokeremote 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<String, String> map = new HashMap<String, String>();

        Map<Object, Object> attributes =new HashMap<Object, Object>();

        map.put(Constants.SIDE_KEY,Constants.CONSUMER_SIDE);

        map.put(Constants.DUBBO_VERSION_KEY,Version.getVersion());

       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<String>(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 prifix =StringUtils.getServiceKey(map);

        if (methods != null &&methods.size() > 0) {

            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, prifix + "." + method.getName());

                checkAndConvertImplicitConfig(method,map, attributes);

            }

        }

        //attributes通过系统context进行存储.

       StaticContext.getSystemContext().putAll(attributes);

        ref = createProxy(map);

   }

基本意思就是集成各种配置,比如类名、方法、版本等等,组成一个map,最终通过createProxy()方法生成代理类,createProxy()方法的代码如下:

   @SuppressWarnings({"unchecked", "rawtypes","deprecation"})

   private T createProxy(Map<String, String> map) {

        URL tmpUrl = new URL("temp","localhost", 0, map);

        final boolean isJvmRefer;

        if (isInjvm() == null) {

            if (url != null &&url.length() > 0) { //指定URL的情况下,不做本地引用

                isJvmRefer = false;

            } else if(InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {

                //默认情况下如果本地有服务暴露,则引用本地服务.

                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 injvmservice " + interfaceClass.getName());

            }

        } else {

            if (url != null &&url.length() > 0) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL

                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 { // 通过注册中心配置拼装URL

                List<URL> us =loadRegistries(false);

                if (us != null &&us.size() > 0) {

                    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 == null || urls.size()== 0) {

                    throw newIllegalStateException("No such any registry to reference " +interfaceName + " on the consumer " + NetUtils.getLocalHost() +" use dubbo version " + Version.getVersion() + ", please config<dubbo:registry address=\"...\" /> to your springconfig.");

                }

            }

 

            if (urls.size() == 1) {

                invoker =refprotocol.refer(interfaceClass, urls.get(0));

            } else {

                List<Invoker<?>>invokers = new ArrayList<Invoker<?>>();

               URL registryURL =null;

                for (URL url : urls) {

                   invokers.add(refprotocol.refer(interfaceClass, url));

                    if(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {

                        registryURL = url; // 用了最后一个registryurl

                    }

                }

                if (registryURL != null) { // 有 注册中心协议的URL

                    // 对有注册中心的Cluster只用 AvailableCluster

                    URL u = registryURL.addParameter(Constants.CLUSTER_KEY,AvailableCluster.NAME);

                    invoker = cluster.join(new StaticDirectory(u, invokers));

                } else { // 不是 注册中心的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 dubboservice " + interfaceClass.getName() + " from url " +invoker.getUrl());

        }

        // 创建服务代理

        return (T)proxyFactory.getProxy(invoker);

   }

一开始调用isInjvm()方法判断目标接口是否在本地就有,如果本地就有,直接调用本地的接口。

如果本地没有,就在配置中找有没有用户指定的url,如果指定了就使用用户指定的url提供的接口。

如果没有指定url,则从注册中心中获得目标url列表。

如果urls.size()==1,则直接用这个url获得invoker,这个invoker就是最后用来创建动态代理用的。

当urls.size()>1时,有registryURL属性,如果配置了注册中心协议Protocol,则只用AvailableCluster得到invoker。

cluster.join()方法是用来获得invoker的,cluster属性的定义:

private transient volatile Invoker<?> invoker;

Invoker是个接口,根据配置的不同会使用不同的实现类,比如上面的AvailableCluster,他的join()方法是这样的:

   public <T> Invoker<T> join(Directory<T> directory)throws RpcException {

        return new AbstractClusterInvoker<T>(directory) {

            public Result doInvoke(Invocationinvocation, List<Invoker<T>> invokers, LoadBalance loadbalance)throws RpcException {

                for (Invoker<T> invoker :invokers) {

                    if (invoker.isAvailable()){

                        returninvoker.invoke(invocation);

                    }

                }

                throw new RpcException("No provider available in " + invokers);

            }

        };

   }

实际上这个join()方法返回了一个AbstractClusterInvoker对象,并重写了他的doInvoke()方法,这个方法在动态代理实际被调用时会用到。

现在回到createProxy()方法,最后用得到的invoker通过proxyFactory创建动态代理,至此动态代理就创建完了。

 

消费端动态代理部分

当我们在代码中配置好的SequenceService进行远程调用时,实际上调用的是对应Invoker的invoke()方法,invoker是一个接口,对于这个接口的实现大概是这样的:

Invoker

----AbstractInvoker

----AbstractClusterInvoker

----AbstractProxyInvoker

----DelegateInvoker

----MockClusterInvoker

----MergeableClusterInvoker

----InvokerListenerAdapter

----InvokerListenerAdapter

……

还有很多

AbstractInvoker就是用来远程通信的Invoker

AbstractClusterInvoker是provider是集群时使用Invoker,比AbstractInvoker多了负载均衡,选择provider的过程,最终确定了调用的provider之后还是会调用AbstractInvoker中的invoke()方法。

我们先看AbstractClusterInvoker的invoke()方法:

    public Result invoke(final Invocation invocation) throws RpcException {


       checkWhetherDestroyed();


        LoadBalanceloadbalance;
 

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

        }

       RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);

        return doInvoke(invocation, invokers, loadbalance);

    }

首先判断当前consumer是否已经destory了,然后用list(invocation)方法获得所有的provider信息,获得负载均衡算法LoadBalance,设置同步属性,最后调用doInvoke方法。

AbstractClusterInvoker的doInvoke()方法是个抽象方法:

protected abstract Result doInvoke(Invocation invocation,List<Invoker<T>> invokers,

                                      LoadBalance loadbalance) throws RpcException;

他的子类有很多,比如:

AvailableClusterInvoker 选择第一个可用的provider。 

FailBackClusterInvoker失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。

FailfastClusterInvoker快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。

FailoverClusterInvoker失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。

FailsafeClusterInvoker失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。

ForkingClusterInvoker并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。

具体使用哪个得看配置


我们以之前提到的AvailableClusterInvoker为例,看一下doInvoke()方法:

    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,LoadBalance loadbalance) throws RpcException {

        for(Invoker<T> invoker : invokers) {

            if(invoker.isAvailable()) {

                return invoker.invoke(invocation);

            }

        }

        throw new RpcException("No provider available in " + invokers);

    }

就是判断invoker是否可用,可用就直接调用invoker的invoke()方法,实际上调用的还是AbstractInvoker的invoke()方法,如果不是集群就直接调这个方法了,该方法代码如下:

    public Result invoke(Invocation inv) throws RpcException {

        if(destroyed.get()) {

            throw new RpcException("Rpc invoker for service " + this + " on consumer" + NetUtils.getLocalHost()

                    +" use dubbo version " + Version.getVersion()

                    +" is DESTROYED, can not be invoked any more!");

        }

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

        }

       RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);


        try {

            return doInvoke(invocation);

        } catch(InvocationTargetException e) { // biz exception

            Throwablete = e.getTargetException();

            if (te ==null) {

                return new RpcResult(e);

            } else {

                if (te instanceof RpcException) {

                   ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);

                }

                return new RpcResult(te);

            }

        } catch(RpcException e) {

            if(e.isBiz()) {

                return new RpcResult(e);

            } else {

                throw e;

            }

        } catch(Throwable e) {

            return new RpcResult(e);

        }

    }

还是先判断consumer是否是destory的,其实destroyed是destory的过去分词,不是人家拼错了。

然后经历一堆和AbstractClusterInvoker的invoke一样的参数设置,最后调用doInvoke()方法,而且这个方法在这个Invoker里面也是抽象的。

AbstractInvoker的doInvoke()方法在DubboInvoker类里面有具体实现,这个DubboInvoker是AbstractInvoker的子类,doInvoke()方法如下:

    @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(newFutureAdapter<Object>(future));

                return new RpcResult();

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

        }

    }

在经过一堆的设置参数(地址、版本)之后,dubbo获得了两个参数,isAsync和isOneway,isAsync为true时代表异步调用,isOneway为true时代表没有返回值。

当isOneway为true时,调用send()方法然后返回一个空的RpcResult,ExchangeClient的send()方法就是用来把消息发给provider的,send()方法的返回值类型是void。

而当isAsync为true时,设置了一个ResponseFuture之后返回一个空的RpcResult

最后的else就是普通的同步调用,不需要设置Future,一直等到provider端返回处理结果,currentClient.request方法负责把请求发出。

 ExchangeClient是个接口,request()方法的实现类在HeaderExchangeClient类中,HeaderExchangeClient的request()方法只有一行,直接调用了HeaderExchangeChannel的request方法,这个request方法如下:

    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 + " isclosed!");

        }

        // 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;

    }

其中的channel就是dubbo集成的Netty的Channel类,负责服务器间消息传输,这个类在dubbo中和netty中都能找到,这里调用了他的send()方法。

Channel的send()方法来自EndPoint接口

Channel接口实现了EndPoint接口

AbstractChannel抽象类实现了Channel接口,然而他的send()方法的功能只是判断当前channel是否已关闭

    public void send(Object message, boolean sent) throws RemotingException {

        if (isClosed()){

            throw new RemotingException(this, "Failed to send message "

                    +(message == null ? "" : message.getClass().getName()) + ":"+ message

                    +", cause: Channel closed. channel: " + getLocalAddress() + "-> " + getRemoteAddress());

        }

    }

最后NettyChannel类继承了AbstractChannel类,重写了父类的send()方法,代码如下:

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

        }

    }

一开始调用了父类的send()方法,判断是否关闭

channel.write()方法就是Channel负责发送消息的方法,至此,消息只要再通过一些事件处理器(主要是编码),就可以发到provider端了。

 

消费端事件处理器部分

NettyClient在初始化时添加了三个事件处理器用来处理发送消息和接收消息的事件,分别是NettyCodecAdapter.DeCoder,NettyCodecAdapter.Encoder,NettyHandler,代码在NettyClient类的doOpen()方法里:

    @Override

    protected void doOpen() throws Throwable {

       NettyHelper.setNettyLoggerFactory();

        bootstrap = new ClientBootstrap(channelFactory);

        // config

        // @see org.jboss.netty.channel.socket.SocketChannelConfig

        bootstrap.setOption("keepAlive",true);

       bootstrap.setOption("tcpNoDelay", true);

       bootstrap.setOption("connectTimeoutMillis", getTimeout());

        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);

       bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            public ChannelPipeline getPipeline() {

               NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(),NettyClient.this);

               ChannelPipeline pipeline = Channels.pipeline();

               pipeline.addLast("decoder", adapter.getDecoder());

               pipeline.addLast("encoder", adapter.getEncoder());

               pipeline.addLast("handler", nettyHandler);

                returnpipeline;

            }

        });

    }

几种事件处理器的在添加时顺序是DeCoder,Encoder,NettyHandler。

当线程给对方发送信息时,叫做下行事件,下行事件会先经过NettyHandler再经过Encoder。

当线程接收对方发来的信息时,叫做上行事件,上行事件会先经过DeCoder再经过NettyHandler。

在调用Channel.write()时,会调用事件处理器中的NettyHandler和Encoder,反过来当provider给consumer返回信息时调用的是DeCoder和NettyHandler。

 

第一步,NettyHandler的writeRequested方法会首先被调用:

    @Override

    public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

       super.writeRequested(ctx, e);

        NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler);

        try {

           handler.sent(channel, e.getMessage());

        } finally {

           NettyChannel.removeChannelIfDisconnected(ctx.getChannel());

        }

    }

这里是进行一些dubbo的回调功能。

第二步是调用NettyCodecAdapter.Encoder,encoder的定义和实现类就在NettyCodecAdapter类中:

    private final ChannelHandler encoder = new InternalEncoder();


    private final Codec2codec;


    @Sharable

    private class InternalEncoder extends OneToOneEncoder {


        @Override

        protected Object encode(ChannelHandlerContext ctx, Channel ch, Object msg) throws Exception {

           com.alibaba.dubbo.remoting.buffer.ChannelBuffer buffer =

                    com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(1024);

           NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler);

            try {

               codec.encode(channel, buffer, msg);

            } finally {

               NettyChannel.removeChannelIfDisconnected(ch);

            }

            return ChannelBuffers.wrappedBuffer(buffer.toByteBuffer());

        }

    }

Codec2是提供encode和decode的接口,该接口由DubboCodec类实现,而具体的实现代码在DubboCodec类的父类ExchangeCodec中:

    public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {

        if (msg instanceof Request) {

           encodeRequest(channel, buffer, (Request) msg);

        } else if (msg instanceof Response) {

            encodeResponse(channel,buffer, (Response) msg);

        } else {

           super.encode(channel, buffer, msg);

        }

    }

在发起调用时,msg是一个Request,调用encodeRequest()方法:

    protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {

        Serialization serialization = getSerialization(channel);

        // header.

        byte[] header =new byte[HEADER_LENGTH];

        // set magicnumber.

       Bytes.short2bytes(MAGIC, header);

 
        // set requestand serialization flag.

        header[2] =(byte) (FLAG_REQUEST | serialization.getContentTypeId());


        if(req.isTwoWay()) header[2] |= FLAG_TWOWAY;

        if (req.isEvent()) header[2] |= FLAG_EVENT;

 
        // set requestid.

       Bytes.long2bytes(req.getId(), header, 4);

 
        // encoderequest data.

        int savedWriteIndex = buffer.writerIndex();

       buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);

       ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);

        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);

        if(req.isEvent()) {

           encodeEventData(channel, out, req.getData());

        } else {

           encodeRequestData(channel, out, req.getData());

        }

       out.flushBuffer();

        bos.flush();

        bos.close();

        int len =bos.writtenBytes();

       checkPayload(channel, len);

       Bytes.int2bytes(len, header, 12);

 

        // write

       buffer.writerIndex(savedWriteIndex);

       buffer.writeBytes(header); // write header.

       buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);

    }

这个方法写的是把请求序列化为二进制的过程,其中的encodeRequestData()方法,经过了好几个只有一行的方法调用,最终执行的是ExchangeCodec类的如下方法:

    protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {

       out.writeObject(data);

    }

至此数据会被发送到provider端。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值