配色: 字号:
Spring Http调用的实现
2016-12-05 | 阅:  转:  |  分享 
  
SpringHttp调用的实现

1:SpringHttp设计思想

最近在研究公司自己的一套rpc远程调用框架,看到其内部实现的设计思想依赖于spring的远端调用的思想,所以闲来无事,就想学习下,并记录下。



作为spring远端调用的实现,最为简单的应该是通过http调用的实现,在这种依赖中不会依赖第三方等相关组件,调用者只需要配置相关http的协议



就可以实现,简单的配置,就可以使用spring的IOC容器的bean的定义等等思想去调用,简单,方便,无需写更多的http相关的代码,



比较适合内部通信系统之间的调用。



在日常开发中,经常会遇到各种内部系统之间的通讯调用,其实可以使用如下几种设计方式。不过,最简单的应该是spring自带的http模式,然后自己封装



打包成客户端jar等等,共客户端调用



image







其实在日常调用实现中,可以通过若干种设计都可以完成客户端与服务端之间的调用,如



阿里的db中间件就是使用的是类似的通讯模式,不过没有研究过



image



公司内部使用的是如下的方式进行通讯,可以通过监控软件来进行对Q的跟踪,在处理大数据高并发的时候,良好的Q中间件及Java中封装异步处理,解决了数据库以及各方面的瓶颈压力,不过,也有缺点,各个应用之间的事务是无法控制,只能通过事后补偿处理。综合来看,还是很好的设计



image



先来说说springHttp协议吧.



2:客户端

在客户端中设计了HttpInvokerProxyFactoryBean,这是一个代理工厂bean(ProxyFactoryBean),它会使用springaop来对http调用器的客户端进行封装,既然使用了aop,就会使用到代理对象,并为代理方法设置相应的拦截器。HttpInvokerProxyFactoryBean中,通过afterPropertiesSet来启动远端调用基础设施的建立等,代理拦截器HttpInvokerClientInterceptor,HttpInvokerClientInterceptor中会封装客户端的基本实现,如http请求链接,请求对象序列化,请求传送到服务端,在收到拦截器的时候,同样也会将服务器端发送过来http响应反序列化,并且把远端调用的服务器端返回的对象交给应用使用,完成一个http请求的基本实现。



Http调用器是基于http协议提供的远端调用方案,使用http调用器和使用Javarmi一样的基础配置模块







HttpInvokerProxyFactoryBean具体实现如下图继承了FactoryBean,使用HttpInvokerProxyFactoryBean需要设置相应的bean对代理工厂的配置

设置远程服务的url地址,设置远端服务的的接口,然后把这个代理工厂设置到客户端应用的bean的remoteService属性中,有了这个设置,客户端应用配置就已经配置好了,就可以像调用本地一样,享用远端服务了



复制代码



http://localhost:8080/xxxx/xxx

com.abc.cc.ddd.ee









复制代码

HttpInvokerProxyFactoryBean中封装对应的远端服务信息,域名,端口,服务所在URL,这些都是远端服务调用所需要的信息,同时,由于使用httpInvoker,所以在URL指定的协议中是http协议,对访问远端服务调用的客户端而言,只要持有HttpInvokerProxyFactoryBean提供的代理对象,就可以方便的使用远端调用,使用起来如本地一样,远端调用发送的数据通信及远端服务交互,都被proxy代理类进行了封装,对客户端是透明的,这些封装主要都是在HttpInvokerProxyFactoryBean进行封装处理的。



image



从图可以知道,当服务启动,系统在spring容器里面自动初始化该代理对象,自动执行afterPropertiesSet相关方法

HttpInvokerProxyFactoryBean是如何封装并将数据传输到服务端的?



复制代码

publicclassHttpInvokerProxyFactoryBeanextendsHttpInvokerClientInterceptorimplementsFactoryBean{



privateObjectserviceProxy;



//代码省去若干代码省去若干代码省去若干代码省去若干

@Override

publicvoidafterPropertiesSet(){

//初始化执行http配置加载等,为后续发送到服务端做准备工作

super.afterPropertiesSet();

//获取在客户端配置的接口,判断接口是否配置,此处的父类进行了类的加载配置等,

//在此处,不是一个配置,而是一个具体的接口类

if(getServiceInterface()==null){

thrownewIllegalArgumentException("Property''serviceInterface''isrequired");

}

//将相关参数,相应的类加载的信息,以及指定具体的客户端实现类代理

this.serviceProxy=newProxyFactory(getServiceInterface(),this).getProxy(getBeanClassLoader());

}





publicObjectgetObject(){

returnthis.serviceProxy;

}



publicClassgetObjectType(){

returngetServiceInterface();

}



publicbooleanisSingleton(){

returntrue;

}

}

复制代码

ProxyFactory所指定的HttpInvokerClientInterceptor拦截器中执行的invoke方法



复制代码

//具体调用执行的方法

publicObjectinvoke(MethodInvocationmethodInvocation)throwsThrowable{

if(AopUtils.isToStringMethod(methodInvocation.getMethod())){

return"HTTPinvokerproxyforserviceURL["+getServiceUrl()+"]";

}

//创建远端服务所需要的参数信息等,格式是spring自己实现的,创建工厂等

RemoteInvocationinvocation=createRemoteInvocation(methodInvocation);

RemoteInvocationResultresult;

try{

//调用服务端,发送请求

result=executeRequest(invocation,methodInvocation);

}

catch(Throwableex){

throwconvertHttpInvokerAccessException(ex);

}

try{

//将服务端的返回信息所需要的对象等

returnrecreateRemoteInvocationResult(result);

}

catch(Throwableex){

if(result.hasInvocationTargetException()){

throwex;

}

else{

thrownewRemoteInvocationFailureException("Invocationofmethod["+methodInvocation.getMethod()+

"]failedinHTTPinvokerremoteserviceat["+getServiceUrl()+"]",ex);

}

}

}

复制代码





上述代码中主要操作:封装发送的接口等

RemoteInvocationFactory>>createRemoteInvocation(MethodInvocationmethodInvocation);

RemoteInvocation>>(RemoteInvocation(StringmethodName,Class[]parameterTypes,Object[]arguments))

DefaultRemoteInvocationFactory>>createRemoteInvocation(MethodInvocationmethodInvocation)



复制代码

/

CreateanewRemoteInvocationforthegivenAOPmethodinvocation.

@parammethodInvocationtheAOPinvocationtoconvert

/

RemoteInvocation>>(RemoteInvocation(StringmethodName,Class[]parameterTypes,Object[]arguments))具体实现

publicRemoteInvocation(MethodInvocationmethodInvocation){

this.methodName=methodInvocation.getMethod().getName();

this.parameterTypes=methodInvocation.getMethod().getParameterTypes();

this.arguments=methodInvocation.getArguments();

}

执行发送

HttpInvokerRequestExecutor-->>AbstractHttpInvokerRequestExecutor类具体实现

publicfinalRemoteInvocationResultexecuteRequest(

HttpInvokerClientConfigurationconfig,RemoteInvocationinvocation)throwsException{



ByteArrayOutputStreambaos=getByteArrayOutputStream(invocation);

if(logger.isDebuwww.wang027.comgEnabled()){

logger.debug("SendingHTTPinvokerrequestforserviceat["+config.getServiceUrl()+

"],withsize"+baos.size());

}

returndoExecuteRequest(config,baos);

}

复制代码

具体流程图如下:

客户端请求配置发送请求



image







3:服务端

在服务端中设计了HttpInvokerServiceExporter,通过ServiceExporter来导出远端的服务对象,由于需要处理http请求,所以其需要依赖springMVC模块来实现,会封装mvc框架的dispatchServlet,并设置相应的控制器。这个控制器执行相应的http请求处理,比如接收服务请求,将服务请求对象反序列化,交给服务端对象完成请求,最后把生成的结果通过序列化通过http协议返回到客户端。



服务端配置:



复制代码















com.abc.cc.ddd.ee





复制代码

springhttp的服务端接收是如何响应的?主要是使用HttpInvokerServiceExporter



复制代码

publicvoidhandleRequest(HttpServletRequestrequest,HttpServletResponseresponse)

throwsServletException,IOException{



try{

//封装请求对象,将其转换成远程调用对象

RemoteInvocationinvocation=readRemoteInvocation(request);

//执行请求并创建返回对象

RemoteInvocationResultresult=invokeAndCreateResult(invocation,getProxy());

//返回到客户端

writeRemoteInvocationResult(request,response,result);

}

catch(ClassNotFoundExceptionex){

thrownewNestedServletException("Classnotfoundduringdeserialization",ex);

}

}

复制代码

执行代码的逻辑并返回,此处代码如下



复制代码

RemoteInvocation



publicObjectinvoke(ObjecttargetObject)

throwsNoSuchMethodException,IllegalAccessException,InvocationTargetException{



Methodmethod=targetObject.getClass().getMethod(this.methodName,this.parameterTypes);

returnmethod.invokwww.baiyuewang.nete(targetObject,this.arguments);

}

复制代码

写入返回到客户端



复制代码

HttpInvokerServiceExporter

protectedvoidwriteRemoteInvocationResult(

HttpServletRequestrequest,HttpServletResponseresponse,RemoteInvocationResultresult,OutputStreamos)

throwsIOException{



ObjectOutputStreamoos=createObjectOutputStream(decorateOutputStream(request,response,os));

try{

doWriteRemoteInvocationResult(result,oos);//调用父类RemoteInvocationSerializingExporter

}

finally{

oos.close();

}

}



RemoteInvocationSerializingExporter



protectedvoiddoWriteRemoteInvocationResult(RemoteInvocationResultresult,ObjectOutputStreamoos)

throwsIOException{



oos.writeObject(result);

}

献花(0)
+1
(本文系thedust79首藏)