1. Caucho

1.1 概况

spring-remoting代码的情况如下:

本节近分析caucho模块。

1.2 分类

其中以hession为例,Hessian远程服务调用过程:

                          Hessian远程服务调用过程

1.2.1 客户端

BurlapProxyFactoryBean,BurlapClientInterceptor;

HessianProxyFactoryBean,HessianClientInterceptor;

HessianProxyFactoryBean继承自HessianClientInterceptor,间接封装了HessianProxyFactory。HessianProxyFactory是hessian的client实现类,

示例:

public interface Basic {public String hello();
}import com.caucho.hessian.client.HessianProxyFactory;public class BasicClient {public static void main(String []args)throws Exception{String url = "http://www.caucho.com/hessian/test/basic";HessianProxyFactory factory = new HessianProxyFactory();  Basic basic = (Basic) factory.create(Basic.class, url);System.out.println("Hello: " + basic.hello());}
}

create方法如下:

/*** Creates a new proxy with the specified URL.  The returned object* is a proxy with the interface specified by api.** <pre>* String url = "http://localhost:8080/ejb/hello");* HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);* </pre>** @param api the interface the proxy class needs to implement* @param url the URL where the client object is located.** @return a proxy to the object with the specified interface.*/public Object create(Class<?> api, URL url, ClassLoader loader){if (api == null)throw new NullPointerException("api must not be null for HessianProxyFactory.create()");InvocationHandler handler = null;    handler = new HessianProxy(url, this, api);return Proxy.newProxyInstance(loader,new Class[] { api,HessianRemoteObject.class },handler);}

其中HessianProxy实现了java的动态代理

/*** Proxy implementation for Hessian clients.  Applications will generally* use HessianProxyFactory to create proxy clients.*/
public class HessianProxy implements InvocationHandler, Serializable {private static final Logger log= Logger.getLogger(HessianProxy.class.getName());protected HessianProxyFactory _factory;private WeakHashMap<Method,String> _mangleMap= new WeakHashMap<Method,String>();private Class<?> _type;private URL _url;/*** Protected constructor for subclassing*/protected HessianProxy(URL url, HessianProxyFactory factory){this(url, factory, null);}/*** Protected constructor for subclassing*/protected HessianProxy(URL url,HessianProxyFactory factory, Class<?> type){_factory = factory;_url = url;_type = type;}
}

最重要的invoke方法如下:

 /*** Handles the object invocation.** @param proxy the proxy object to invoke* @param method the method to call* @param args the arguments to the proxy object*/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 casedif (methodName.equals("equals")&& params.length == 1 && params[0].equals(Object.class)) {Object value = args[0];if (value == null || ! Proxy.isProxyClass(value.getClass()))return Boolean.FALSE;Object proxyHandler = Proxy.getInvocationHandler(value);if (! (proxyHandler instanceof HessianProxy))return Boolean.FALSE;HessianProxy handler = (HessianProxy) proxyHandler;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();elsemangleName = mangleName(method);synchronized (_mangleMap) {_mangleMap.put(method, mangleName);}}InputStream is = null;HessianConnection conn = null;try {if (log.isLoggable(Level.FINER))log.finer("Hessian[" + _url + "] calling " + mangleName); conn = sendRequest(mangleName, args);is = getInputStream(conn);if (log.isLoggable(Level.FINEST)) {PrintWriter dbg = new PrintWriter(new LogWriter(log));HessianDebugInputStream dIs= new HessianDebugInputStream(is, dbg);dIs.startTop2();is = dIs;}AbstractHessianInput in;int code = is.read();if (code == 'H') {int major = is.read();int minor = is.read();in = _factory.getHessian2Input(is);Object value = in.readReply(method.getReturnType());return value;}else if (code == 'r') {int major = is.read();int minor = is.read();in = _factory.getHessianInput(is);in.startReplyBody();Object value = in.readObject(method.getReturnType());if (value instanceof InputStream) {value = new ResultInputStream(conn, is, in, (InputStream) value);is = null;conn = null;}elsein.completeReply();return value;}elsethrow new HessianProtocolException("'" + (char) code + "' is an unknown code");} catch (HessianProtocolException e) {throw new HessianRuntimeException(e);} finally {try {if (is != null)is.close();} catch (Exception e) {log.log(Level.FINE, e.toString(), e);}try {if (conn != null)conn.destroy();} catch (Exception e) {log.log(Level.FINE, e.toString(), e);}}}

发送http请求

 /*** Sends the HTTP request to the Hessian connection.*/protected HessianConnection sendRequest(String methodName, Object []args)throws IOException{HessianConnection conn = null;conn = _factory.getConnectionFactory().open(_url);boolean isValid = false;try {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));HessianDebugOutputStream dOs = new HessianDebugOutputStream(os, dbg);dOs.startTop2();os = dOs;}AbstractHessianOutput out = _factory.getHessianOutput(os);out.call(methodName, args);out.flush();conn.sendRequest();isValid = true;return conn;} finally {if (! isValid && conn != null)conn.destroy();}}

创建http连接代码

 /*** Opens a new or recycled connection to the HTTP server.*/public HessianConnection open(URL url)throws IOException{if (log.isLoggable(Level.FINER))log.finer(this + " open(" + url + ")");URLConnection conn = url.openConnection();// HttpURLConnection httpConn = (HttpURLConnection) conn;// httpConn.setRequestMethod("POST");// conn.setDoInput(true);long connectTimeout = _proxyFactory.getConnectTimeout();if (connectTimeout >= 0)conn.setConnectTimeout((int) connectTimeout);conn.setDoOutput(true);long readTimeout = _proxyFactory.getReadTimeout();if (readTimeout > 0) {try {conn.setReadTimeout((int) readTimeout);} catch (Throwable e) {}}

1.2.2 服务器端

HessianExporter及其实现类HessianServiceExporter,SimpleHessianServiceExporter.

hessian服务端示例

package hessian.test;import com.caucho.hessian.server.HessianServlet;public class BasicService extends HessianServlet implements Basic {public String hello(){return "Hello, world";}
}

我们来看一下:

HessianServiceExporter

/*** Servlet-API-based HTTP request handler that exports the specified service bean* as Hessian service endpoint, accessible via a Hessian proxy.** <p><b>Note:</b> Spring also provides an alternative version of this exporter,* for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}.** <p>Hessian is a slim, binary RPC protocol.* For information on Hessian, see the* <a href="http://www.caucho.com/hessian">Hessian website</a>.* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>** <p>Hessian services exported with this class can be accessed by* any Hessian client, as there isn't any special handling involved.** @author Juergen Hoeller* @since 13.05.2003* @see HessianClientInterceptor* @see HessianProxyFactoryBean* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter* @see org.springframework.remoting.rmi.RmiServiceExporter*/

处理客户端请求的方法:

/*** Processes the incoming Hessian request and creates a Hessian response.*/@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {if (!"POST".equals(request.getMethod())) {throw new HttpRequestMethodNotSupportedException(request.getMethod(),new String[] {"POST"}, "HessianServiceExporter only supports POST requests"); } response.setContentType(CONTENT_TYPE_HESSIAN); try { invoke(request.getInputStream(), response.getOutputStream()); } catch (Throwable ex) { throw new NestedServletException("Hessian skeleton invocation failed", ex); } }

invoke调用

/*** Actually invoke the skeleton with the given streams.* @param skeleton the skeleton to invoke* @param inputStream the request stream* @param outputStream the response stream* @throws Throwable if invocation failed*/protected void doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)throws Throwable {ClassLoader originalClassLoader = overrideThreadContextClassLoader();try {InputStream isToUse = inputStream;OutputStream osToUse = outputStream; if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) { PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger)); @SuppressWarnings("resource") HessianDebugInputStream dis = new HessianDebugInputStream(inputStream, debugWriter); @SuppressWarnings("resource") HessianDebugOutputStream dos = new HessianDebugOutputStream(outputStream, debugWriter); dis.startTop2(); dos.startTop2(); isToUse = dis; osToUse = dos; } if (!isToUse.markSupported()) { isToUse = new BufferedInputStream(isToUse); isToUse.mark(1); } int code = isToUse.read(); int major; int minor; AbstractHessianInput in; AbstractHessianOutput out; if (code == 'H') { // Hessian 2.0 stream major = isToUse.read(); minor = isToUse.read(); if (major != 0x02) { throw new IOException("Version " + major + "." + minor + " is not understood"); } in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'C') { // Hessian 2.0 call... for some reason not handled in HessianServlet!  isToUse.reset(); in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'c') { // Hessian 1.0 call major = isToUse.read(); minor = isToUse.read(); in = new HessianInput(isToUse); if (major >= 2) { out = new Hessian2Output(osToUse); } else { out = new HessianOutput(osToUse); } } else { throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code); } if (this.serializerFactory != null) { in.setSerializerFactory(this.serializerFactory); out.setSerializerFactory(this.serializerFactory); } if (this.remoteResolver != null) { in.setRemoteResolver(this.remoteResolver); } try { skeleton.invoke(in, out); } finally { try { in.close(); isToUse.close(); } catch (IOException ex) { // ignore  } try { out.close(); osToUse.close(); } catch (IOException ex) { // ignore  } } } finally { resetThreadContextClassLoader(originalClassLoader); } }

调用skeleton的invoke方法

/*** Invoke the object with the request from the input stream.** @param in the Hessian input stream* @param out the Hessian output stream*/public void invoke(Object service,AbstractHessianInput in,AbstractHessianOutput out)throws Exception{ServiceContext context = ServiceContext.getContext();// backward compatibility for some frameworks that don't read// the call type firstin.skipOptionalCall();// Hessian 1.0 backward compatibilityString header;while ((header = in.readHeader()) != null) { Object value = in.readObject(); context.addHeader(header, value); } String methodName = in.readMethod(); int argLength = in.readMethodArgLength(); Method method; method = getMethod(methodName + "__" + argLength); if (method == null) method = getMethod(methodName); if (method != null) { } else if ("_hessian_getAttribute".equals(methodName)) { String attrName = in.readString(); in.completeCall(); String value = null; if ("java.api.class".equals(attrName)) value = getAPIClassName(); else if ("java.home.class".equals(attrName)) value = getHomeClassName(); else if ("java.object.class".equals(attrName)) value = getObjectClassName(); out.writeReply(value); out.close(); return; } else if (method == null) { out.writeFault("NoSuchMethodException", escapeMessage("The service has no method named: " + in.getMethod()), null); out.close(); return; } Class<?> []args = method.getParameterTypes(); if (argLength != args.length && argLength >= 0) { out.writeFault("NoSuchMethod", escapeMessage("method " + method + " argument length mismatch, received length=" + argLength), null); out.close(); return; } Object []values = new Object[args.length]; for (int i = 0; i < args.length; i++) { // XXX: needs Marshal object values[i] = in.readObject(args[i]); } Object result = null; try { result = method.invoke(service, values); } catch (Exception e) { Throwable e1 = e; if (e1 instanceof InvocationTargetException) e1 = ((InvocationTargetException) e).getTargetException(); log.log(Level.FINE, this + " " + e1.toString(), e1); out.writeFault("ServiceException", escapeMessage(e1.getMessage()), e1); out.close(); return; } // The complete call needs to be after the invoke to handle a // trailing InputStream  in.completeCall(); out.writeReply(result); out.close(); }

反射触发类的方法。

BurlapExporter及其实现类BurlapServiceExporter,SimpleBurlapServiceExporter,因已经depressed,故略。

1.3 小结

  Spring封装了hessian客户端和服务端的通用代码,把实现者和调用者作为bean放到spring容器中管理,简化了开发。分析源码的过程中,发现在客户端使用了动态代理,在服务端使用反射,让我们加深了对java基础知识的理解。

转载于:https://www.cnblogs.com/davidwang456/p/5496933.html

spring remoting源码分析--Hessian分析相关推荐

  1. Spring Cloud源码分析(二)Ribbon(续)

    因文章长度限制,故分为两篇.上一篇:<Spring Cloud源码分析(二)Ribbon> 负载均衡策略 通过上一篇对Ribbon的源码解读,我们已经对Ribbon实现的负载均衡器以及其中 ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  4. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  5. spring AOP源码分析(一)

    spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...

  6. Spring源码分析-Spring事务源码分析

    导语      在配置Spring事务管理的时候会用到一个类TransactionInterceptor,从下面的类关系图中可以看到TransactionInterceptor继承了MethodInt ...

  7. 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  8. Spring源码总结与分析

    前言 Spring是什么?它是一个应用程序框架,为应用程序的开发提供强大的支持,例如对事务处理和持久化的支持等:它也是一个bean容器,管理bean对象的整个生命周期,维护bean的各种存在状态,例如 ...

  9. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    概述 我们知道 Spring Boot 能够创建独立的 Spring 应用,内部嵌入 Tomcat 容器(Jetty.Undertow),让我们的 jar 无需放入 Servlet 容器就能直接运行. ...

最新文章

  1. ny520 最大素因子 筛选法求素数
  2. Web性能优化系列(1):Web性能优化分析
  3. 如何画透明位图(转)
  4. c语言从E1到E123遍历,试题.习题__2011年c语言实验与习题集.doc
  5. 经常收到信用卡邀请短信,但为什么总是办不下来?
  6. raspberry pi_每日新闻摘要:新型iMac,NVIDIA的Raspberry Pi竞争对手等
  7. 的使用go_使用 Go 开发 Prometheus Exporter
  8. Java的异常跟踪栈
  9. 一种页面数据错误输入提示方法 【转】
  10. java 给图片添加暗水印_java 实现给图片添加水印
  11. java喷泉编码_Java干货分享使用JS实现简单喷泉效果
  12. Caffe编写Python layer
  13. 用JavaScript验证密码强度
  14. android 系统宏定义,Android.mk宏定义demo【转】
  15. oracle数据库:约束
  16. 四足机器人动力学建模(一)
  17. Wireshark 导出特定分组
  18. 计算机组成原理之概述篇(一)
  19. APP如何借助种子用户运营
  20. 感知机算法在鸢尾花数据集上的实践

热门文章

  1. mysql 查询 distinct_MYSQL查询数据(二)SELECT | DISTINCT
  2. php 论坛_推荐一个基于话题的高性能轻型开源PHP论坛程序
  3. string类有可以调换方向的函数吗_C++中的string类的用法小结
  4. Android中的表格布局
  5. 任务与中断共享资源冲突示例
  6. 职称计算机初级应知应会书,2017专业技术职称申报应知应会.ppt
  7. 逆向链表c语言 abcdef,6-6 求单链表元素序号 (5 分)
  8. leetcode 组合总和
  9. linux 编程博客,Linux系统编程博客参考
  10. 强化学习(四)---基于模型动态规划问题