当前位置 : 主页 > 大数据 > 区块链 >

RPC中客户端动态代理如何实现的?

来源:互联网 收集:自由互联 发布时间:2021-06-22
最近在熟悉工程中用到的RPC框架,碰到一个小问题。在引出该问题前,先简单介绍一下RPC: RPC介绍 我们从一个例子开始。 服务方接口: package com.jzh.rpc.server; public interface IRpcServer { p

最近在熟悉工程中用到的RPC框架,碰到一个小问题。在引出该问题前,先简单介绍一下RPC:

RPC介绍

我们从一个例子开始。
服务方接口:

package com.jzh.rpc.server;

public interface IRpcServer {

    public void work();

}

服务方实现类:

package com.jzh.rpc.server.impl;

import com.jzh.rpc.server.IRpcServer;

public class RpcServerImpl implements IRpcServer{

  @Override
  public void work() {
    System.out.println("you got me");
  }

}

上面代码非常简单,work方法打印you got me
如果上述代码实现在本地,那很简单,我们通过下面代码即可调用RpcServerImpl 的work方法:

package com.jzh.rpc.client;

import com.jzh.rpc.server.IRpcServer;
import com.jzh.rpc.server.impl.RpcServerImpl;

public class RpcClient {

  private IRpcServer prcServer = new RpcServerImpl();

  public void callWork() {
    prcServer.work();
  }

}

如果RpcServerImpl 并不实现在本地,而你仍然想通过上述代码去调用work方法。这就是PRC。

定义

RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
可以看出,我们上面的诉求,刚好符合PRC的定义。

本地请求,要发到远程服务器,首先,要知道远程服务器的地址,其次,数据要在网络中传输,要序列化,转化为字节,然后是网络传输。服务端接收到请求后,首先要反序列化,然后去调用相应的方法,并将结果序列化后再返回给客户端。

通常的做法是服务提供方注册服务信息到zookeeper上。服务消费方在调用时,会到zookeeper上查找提供方的地址信息,然后向提供方发起请求。而网络传输部分,则一般采用流行的网络框架Netty,也解决了序列化的问题。

问题

理解起来,没什么问题。真正实现的时候,就要想想该如何操作了。服务端还好说,netty的eventloop中添加自定义的handler,接受的请求后,由其出寻找是该调用哪个方法。那么客户端呢?如果在我们执行work方法的时候,去调用远程服务器?这里能想到的,就是动态代理了(不了解动态代理的,可以看看这篇文章:http://www.voidcn.com/article/p-xreoixqf-bpg.html)。那么怎么去触发动态代理呢?通过注解吗?看代码,并没有。最后查了网上的资料,原来实现FactoryBean就可以了。

FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。那么我们可以实现一个FactoryBean类,然后重写它的getObject()方法,该getObject方法,生成它的代理类。看下面的例子:

public class RpcConsumerProxyFactoryBean implements FactoryBean {

    //代理的接口名
    private String interfaceName;

    /** * 类描述:代理类处理逻辑 **/
    class InvocationHandlerImpl implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // RPC调用
            System.out.println("RPC调用: " + method.getName());
            return null;
        }

    }

    @Override
    public Object getObject() throws Exception {
        Object proxy = Proxy.newProxyInstance(RpcConsumerProxyFactoryBean.class.getClassLoader(),
                new Class[] { getObjectType() }, new InvocationHandlerImpl());
        return proxy;
    }

    @Override
    public Class getObjectType() {
        try {
            return Class.forName(interfaceName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

在xml中添加:

<bean id="remoteService" class="proxy.RpcConsumerProxyFactoryBean">
        <property name="interfaceName">
            <value>proxy.RemoteService</value>
        </property>
    </bean>

那么程序中remoteService 就是通过FactoryBean创建出来的动态代理类。

根据上述思路,我在代码中查找实现了FactoryBean的类,找倒是找到了,但没在xml和其他任何地方找到医用该类的地方。百思不得其解。最后终于发现,客户端动态代理不是通过实现FactoryBean弄得。。。好一个虚晃一枪。

实际是这样的:

@Bean
    public OrderingService orderingService() throws Exception {
        return orderingServiceBuilder().buildInterface(OrderingService.class, "orderingService");
    }

实际调用了:

public <I, T> I buildInterface(Class<I> ifaceClass, Class<T> targetClass, String beanName) throws Exception {
        RpcClientBuilder<I, T> rpcServiceBuilder = new RpcClientBuilder<I, T>();
        rpcServiceBuilder.setTargetIface(targetClass);
        rpcServiceBuilder.setBeanName(beanName);
        rpcServiceBuilder.setInterfaceClass(ifaceClass);

        ClientService clientService = getClientService();
        rpcServiceBuilder.setClientService(clientService);
        return rpcServiceBuilder.build();
    }

build方法:

public I build() throws Exception {
        ClientProxy<I, T> proxy = new ClientProxy<I, T>();
        proxy.setClientCacheService(getClientCacheService());
        proxy.setBeanName(getBeanName());
        proxy.setTargetIface(getTargetIface());
        proxy.setInterfaceClass(getInterfaceClass());
        proxy.setClientService(getClientService());
        return proxy.createProxy();
    }

终于让我找到你了。。。。

上一篇:深入浅出SOA
下一篇:最简RPC框架实现
网友评论