Hessian源码分析(二)------ HessianProxy

本文详细解析了Hessian Proxy的工作原理,包括客户端如何通过Proxy模式调用远程方法,如何序列化请求并发送,以及如何反序列化响应。特别介绍了invoke方法的实现流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hessian在客户端一块采用Proxy模式,当客户端调用远程接口时,HessianProxy会代理这个动作,在invoke方法中,把客户端请求的方法和参数序列化为预订格式的输出流,主要流程如下图所示:

下面我将详细解析一下invoke源码:

public Object invoke(Object proxy, Method method, Object []args) throws Throwable { String mangleName; synchronized (_mangleMap) { mangleName = _mangleMap.get(method); } if (mangleName == null) { String methodName = method.getName(); Class []params = method.getParameterTypes(); // equals and hashCode are special cased if (methodName.equals("equals") && params.length == 1 && params[0].equals(Object.class)) { Object value = args[0]; if (value == null || ! Proxy.isProxyClass(value.getClass())) return new Boolean(false); HessianProxy handler = (HessianProxy) Proxy.getInvocationHandler(value); return new Boolean(_url.equals(handler.getURL())); } else if (methodName.equals("hashCode") && params.length == 0) return new Integer(_url.hashCode()); else if (methodName.equals("getHessianType")) return proxy.getClass().getInterfaces()[0].getName(); else if (methodName.equals("getHessianURL")) return _url.toString(); else if (methodName.equals("toString") && params.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不会走远程调用,而是直接返回。

接着往下看:

public Object invoke(Object proxy, Method method, Object []args) throws Throwable { ...... InputStream is = null; URLConnection conn = null; HttpURLConnection httpConn = null; try { conn = sendRequest(mangleName, args); ...... } catch (HessianProtocolException e) { throw new HessianRuntimeException(e); } finally { ...... } }

这段主要是把方法名和参数序列化为网络输出流,并做网络请求,具体逻辑包装在sendRequest方法中:

protected URLConnection sendRequest(String methodName, Object []args) throws IOException { URLConnection conn = null; conn = _factory.openConnection(_url); boolean isValid = false; try { // Used chunked mode when available, i.e. JDK 1.5. if (_factory.isChunkedPost() && conn instanceof HttpURLConnection) { try { HttpURLConnection httpConn = (HttpURLConnection) conn; httpConn.setChunkedStreamingMode(8 * 1024); } catch (Throwable e) { } } addRequestHeaders(conn); OutputStream os = null; try { os = conn.getOutputStream(); } catch (Exception e) { throw new HessianRuntimeException(e); } if (log.isLoggable(Level.FINEST)) { PrintWriter dbg = new PrintWriter(new LogWriter(log)); os = new HessianDebugOutputStream(os, dbg); } AbstractHessianOutput out = _factory.getHessianOutput(os); out.call(methodName, args); out.flush(); isValid = true; return conn; } finally { if (! isValid && conn instanceof HttpURLConnection) ((HttpURLConnection) conn).disconnect(); } }

sendRequest的主要流程是先初始化网络连接,然后用AbstractHessianOutput包装网络输出流,调用AbstractHessianOutput.call(methodName, args)完成网络输出,这个方法的细节会在hessian io的源码解析中详细分析。

下面接着看invoke方法:

public Object invoke(Object proxy, Method method, Object []args) throws Throwable { ...... is = conn.getInputStream(); AbstractHessianInput in = _factory.getHessianInput(is); in.startReply(); Object value = in.readObject(method.getReturnType()); if (value instanceof InputStream) { value = new ResultInputStream(httpConn, is, in, (InputStream) value); is = null; httpConn = null; } else in.completeReply(); ...... }

这一段主要是把输入流中取得返回值,具体是用AbstractHessianInput包装网络输入流,然后调用AbstractHessianInput.readObject从网络流中反序列化到实际返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值