最近在熟悉工程中用到的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();
}
终于让我找到你了。。。。