RPC中客户端动态代理如何实现的?
2018-02-04 22:46
567 查看
最近在熟悉工程中用到的RPC框架,碰到一个小问题。在引出该问题前,先简单介绍一下RPC:
服务方接口:
服务方实现类:
上面代码非常简单,work方法打印
如果上述代码实现在本地,那很简单,我们通过下面代码即可调用RpcServerImpl 的work方法:
如果RpcServerImpl 并不实现在本地,而你仍然想通过上述代码去调用work方法。这就是PRC。
可以看出,我们上面的诉求,刚好符合PRC的定义。
本地请求,要发到远程服务器,首先,要知道远程服务器的地址,其次,数据要在网络中传输,要序列化,转化为字节,然后是网络传输。服务端接收到请求后,首先要反序列化,然后去调用相应的方法,并将结果序列化后再返回给客户端。
通常的做法是服务提供方注册服务信息到zookeeper上。服务消费方在调用时,会到zookeeper上查找提供方的地址信息,然后向提供方发起请求。而网络传输部分,则一般采用流行的网络框架Netty,也解决了序列化的问题。
FactoryBean跟普通Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。那么我们可以实现一个FactoryBean类,然后重写它的getObject()方法,该getObject方法,生成它的代理类。看下面的例子:
在xml中添加:
那么程序中remoteService 就是通过FactoryBean创建出来的动态代理类。
根据上述思路,我在代码中查找实现了FactoryBean的类,找倒是找到了,但没在xml和其他任何地方找到医用该类的地方。百思不得其解。最后终于发现,客户端动态代理不是通过实现FactoryBean弄得。。。好一个虚晃一枪。
实际是这样的:
实际调用了:
build方法:
终于让我找到你了。。。。
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://blog.csdn.net/sdlyjzh/article/details/78121769)。那么怎么去触发动态代理呢?通过注解吗?看代码,并没有。最后查了网上的资料,原来实现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(); }
终于让我找到你了。。。。
相关文章推荐
- 如何写一个RPC框架(二):利用Bean容器和动态代理简化客户端代码
- 【远程调用框架】如何实现一个简单的RPC框架(三)优化一:利用动态代理改变用户服务调用方式
- 动态代理以及动态代理如何实现AOP
- java 如何实现动态代理(mybatis底层原理)
- 在Spring中,是如何实现 Aop 的,原理:动态代理+cglib 分步图解
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- 分布式Web应用----基于Socket+动态代理实现简单RPC 生产者消费者模型
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP(转)
- Spring如何运用动态代理实现AOP
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- 如何实现JDK动态代理?
- SilverLight企业应用框架设计【四】实体层设计+为客户端动态生成服务代理(自己实现RiaService)
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- 关于在JAVA中如何实现简单的动态代理
- alljoyn:基于java动态代理的RPC实现原理分析
- SprignMVC+myBatis整合+mybatis源码分析+动态代理实现流程+如何根据mapper接口生成其实现类
- 如何从response里面取出向客户端输出的html流-代理模式实现
- 如何实现在已有代码之后添加逻辑之java动态代理
- 什么是动态代理?动态代理是如何实现的?动态代理有哪些应用?
- JAX-RPC学习笔记(2)-通过动态代理客户端访问webservice