Java基础:动态代理在RPC框架中应用

转载请注明出处:jiq•钦's technical Blog 


RPC,远端过程调用。就是调用远端机器上的方法。

原理其实很简单,就是客户端上运行的程序在调用对象方法时,底层将针对该方法的调用转换为TCP/HTTP请求,发送到远端服务器,远端服务器监听固定端口,收到这个TCP/HTTP请求后会解析出相关信息,包括客户端想要调用哪个类的哪个方法,参数是什么等,然后进行对应的调用,将调用结果再通过数据包发回即可。

 

RPC中一般会有一些“契约”的概念,即客户端和服务端双方约定好的接口,表明服务端实现了哪些接口,客户端可以使用这些接口。下面以一个我实现的简单的RPC框架为例说明。

 

一、客户端

客户端一般会创建一个服务访问代理,其实就是这个契约接口类型的对象,下面是一个创建服务代理的例子:

//创建代理,调用服务
IHelloService proxy= (IHelloService)RpcProxyFactory.createProxy(IHelloService.class,"HelloService", 3000);
System.out.println("服务调用结果:"+proxy.sayHello("季义钦"));

 其中createProxy接口的实现如下:

/**
 * 创建远程调用代理
 * @paramobjClass        接口类对象
 * @paramserviceName        服务名称
 * @paramURL        服务地址
 * @paramtimeout        连接超时时限
 * @return
 * @throws Exception
 */
publicstatic Object createProxy(Class<?> objClass, String serviceName, StringURL, int timeout) throws Exception
{
//解析调用地址
String[]urls = URL.split(":");
StringipAddress = urls[1];
intport =Integer.parseInt(urls[2]);                        
 
//创建InvocationHandler
CBIPInvocationHandlerhandler = new CBIPInvocationHandler(ipAddress, port, timeout);
handler.setServiceName(serviceName);
 
//返回代理
returnProxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{objClass}, handler);
}

 很明显可以看到借助的是JavaInvocationHandler动态代理机制,通过Proxy静态方法newProxyInstance返回服务代理。

其中CBIPInvocationHandler是客户端代码的核心,是实现了InvocationHandler接口的Java动态代理,其invoke方法实现如下:

/**
 * 所有方法调用都通过invoke来执行
 */
publicObject invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Objectresult = null;
try
{
//获取调用相关信息
StringbeanName = this.serviceName; //this.targrtObject.getClass().getSimpleName();
StringmethodName = method.getName();
String[]argTypes = createParamSignature(method.getParameterTypes());
 
//发起远程方法同步调用,传递调用信息
        result = invokeSync(beanName,methodName, argTypes, args);
}
catch(Exceptionee)
{                
ee.printStackTrace();
returnnull;
}
 
returnresult;
}

 invokeSync方法作用就是将调用相关信息通过Mina框架(JavaNIO框架,异步事件驱动,提供TCP/UDP通信的高层抽象API)发送出去。

 

二、服务端

通过Mina框架实现的服务端程序获取来自客户端的方法调用的请求数据包后,解析出调用相关信息。

/**
     * 收到来自客户端的消息
     */
    @Override
    public void messageReceived(IoSessionsession, Object message) throws Exception {
       
           if(message instanceofCbipTcpRequest)
           {
                   CbipTcpRequestrequest = (CbipTcpRequest)message;
                   
                   
                   try
                   {
                           //读取spring配置文件根据服务名称获取服务全限定名,然后反射出目标实例
                   ApplicationContextctx = new ClassPathXmlApplicationContext("dsf_config.xml"); 
                   ServiceConfigservice = (ServiceConfig)ctx.getBean(request.getBeanName());
                   Class<?>objClass = Class.forName(service.getServiceName());
                   Objectobj = objClass.newInstance();
                   
                   //调用指定的方法
                   CBIPSkeletonskeleton = new CBIPSkeleton(obj, obj.getClass());
                   Objectresult = skeleton.invoke(request.getMethodName(), request.getArgs());
                   
                   //回复
               CbipTcpResponse response= new CbipTcpResponse();
               response.setRequestID(request.getId());        //        请求ID
               response.setBeanName(request.getBeanName());
               response.setMethodName(request.getMethodName());
               response.setResult(result);
                   session.write(response);        //类似套接字
                   }catch(Exceptionee)
                   {
                           ee.printStackTrace();                            
                   }                           
           }          
    }

  这个数据包接收函数主要三个进行步骤:

1)通过收到的客户端请求知道调用哪个类,从配置文件中读取该类的全限定名加载到JVM,反射出该类实例;

2)通过反射出来的实例进行方法调用;

3)通过Mina框架返回调用结果;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值