Hessian源码分析(二)------ HessianProxy
Hessian在客户端一块采用Proxy模式,当客户端调用远程接口时,HessianProxy会代理这个动作,在invoke方法中,把客户端请求的方法和参数序列化为预订格式的输出流,主要流程如下图所示:
下面我将详细解析一下invoke源码:
- publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
- throwsThrowable
- {
- StringmangleName;
- synchronized(_mangleMap){
- mangleName=_mangleMap.get(method);
- }
- if(mangleName==null){
- StringmethodName=method.getName();
- Class[]params=method.getParameterTypes();
- //equalsandhashCodearespecialcased
- if(methodName.equals("equals")
- &¶ms.length==1&¶ms[0].equals(Object.class)){
- Objectvalue=args[0];
- if(value==null||!Proxy.isProxyClass(value.getClass()))
- returnnewBoolean(false);
- HessianProxyhandler=(HessianProxy)Proxy.getInvocationHandler(value);
- returnnewBoolean(_url.equals(handler.getURL()));
- }
- elseif(methodName.equals("hashCode")&¶ms.length==0)
- returnnewInteger(_url.hashCode());
- elseif(methodName.equals("getHessianType"))
- returnproxy.getClass().getInterfaces()[0].getName();
- elseif(methodName.equals("getHessianURL"))
- return_url.toString();
- elseif(methodName.equals("toString")&¶ms.length==0)
- return"HessianProxy["+_url+"]";
- if(!_factory.isOverloadEnabled())
- mangleName=method.getName();
- else
- mangleName=mangleName(method);
- synchronized(_mangleMap){
- _mangleMap.put(method,mangleName);
- }
- }
- ......
- }
这是invoke的开头,主要干的事情是把methodName缓存起来和过滤一些特殊调用,java反射是个比较耗性能的操作,把methodName缓存起来可以避免每次调用都要从method里得到methodName。另外,对equals、hashCode、getHessianType、getHessianURL等特殊方法的远程调用,HessianProxy不会走远程调用,而是直接返回。
接着往下看:
- publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
- throwsThrowable
- {
- ......
- InputStreamis=null;
- URLConnectionconn=null;
- HttpURLConnectionhttpConn=null;
- try{
- conn=sendRequest(mangleName,args);
- ......
- }catch(HessianProtocolExceptione){
- thrownewHessianRuntimeException(e);
- }finally{
- ......
- }
- }
这段主要是把方法名和参数序列化为网络输出流,并做网络请求,具体逻辑包装在sendRequest方法中:
- protectedURLConnectionsendRequest(StringmethodName,Object[]args)
- throwsIOException
- {
- URLConnectionconn=null;
- conn=_factory.openConnection(_url);
- booleanisValid=false;
- try{
- //Usedchunkedmodewhenavailable,i.e.JDK1.5.
- if(_factory.isChunkedPost()&&conninstanceofHttpURLConnection){
- try{
- HttpURLConnectionhttpConn=(HttpURLConnection)conn;
- httpConn.setChunkedStreamingMode(8*1024);
- }catch(Throwablee){
- }
- }
- addRequestHeaders(conn);
- OutputStreamos=null;
- try{
- os=conn.getOutputStream();
- }catch(Exceptione){
- thrownewHessianRuntimeException(e);
- }
- if(log.isLoggable(Level.FINEST)){
- PrintWriterdbg=newPrintWriter(newLogWriter(log));
- os=newHessianDebugOutputStream(os,dbg);
- }
- AbstractHessianOutputout=_factory.getHessianOutput(os);
- out.call(methodName,args);
- out.flush();
- isValid=true;
- returnconn;
- }finally{
- if(!isValid&&conninstanceofHttpURLConnection)
- ((HttpURLConnection)conn).disconnect();
- }
- }
sendRequest的主要流程是先初始化网络连接,然后用AbstractHessianOutput包装网络输出流,调用AbstractHessianOutput.call(methodName, args)完成网络输出,这个方法的细节会在hessian io的源码解析中详细分析。
下面接着看invoke方法:
- publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
- throwsThrowable
- {
- ......
- is=conn.getInputStream();
- AbstractHessianInputin=_factory.getHessianInput(is);
- in.startReply();
- Objectvalue=in.readObject(method.getReturnType());
- if(valueinstanceofInputStream){
- value=newResultInputStream(httpConn,is,in,(InputStream)value);
- is=null;
- httpConn=null;
- }
- else
- in.completeReply();
- ......
- }
这一段主要是把输入流中取得返回值,具体是用AbstractHessianInput包装网络输入流,然后调用AbstractHessianInput.readObject从网络流中反序列化到实际返回值。