博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring remoting源码分析--Hessian分析
阅读量:6078 次
发布时间:2019-06-20

本文共 14759 字,大约阅读时间需要 49 分钟。

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.   *   * 
   * String url = "http://localhost:8080/ejb/hello");   * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);   * 
* * @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
_mangleMap = new WeakHashMap
(); 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 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 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(); else mangleName = 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; } else in.completeReply(); return value; } else throw 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. * * 

Note: Spring also provides an alternative version of this exporter, * for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}. * *

Hessian is a slim, binary RPC protocol. * For information on Hessian, see the * Hessian website. * Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above. * *

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.     */    @Override    public 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 first    in.skipOptionalCall();    // Hessian 1.0 backward compatibility    String 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基础知识的理解。

 

转载地址:http://yshgx.baihongyu.com/

你可能感兴趣的文章
Flask下载文件
查看>>
java基础学习_基础语法(上)02_day03总结
查看>>
乐视印度公司裁员80%,全球化扩张遭遇滑铁卢,它还能撑多久?
查看>>
weex sdk集成到Android工程二. weex sdk集成到Android工程
查看>>
Git工程实践(二)多账号配置
查看>>
鱼鹰软件签约老牌传播机构思艾传播集团
查看>>
线程(杂)
查看>>
未来杯高校AI挑战赛激战正酣 金山云全程提供云资源
查看>>
【资讯】福布斯:旅行积分计划是区块链主要目标,对旅行者来说是好消息
查看>>
高桥智隆:未来机器人将取代智能手机,并成为人类的朋友
查看>>
工信部表示:建立网络数据安全管理体系 强化用户个人信息保护
查看>>
感受真实的华为-记山东CIO智库会员华为之行
查看>>
Spring的依赖注入概述
查看>>
为什么我的联想打印机M7450F换完墨粉之后打印机显示请更换墨粉盒?这是我的墨盒第一次灌粉&#183;、...
查看>>
命运多舛、前途未卜,共享经济年终盘点之网约车
查看>>
研究人员研制出可有效抑制艾滋病病毒的新药,可让病毒几乎检测不出来
查看>>
什么是区块链?超级账本 Brian Behlendorf 从五个方面教你认识
查看>>
独家揭秘:2017中国人工智能与机器人创新大会大咖云集
查看>>
聊聊Dubbo - Dubbo可扩展机制实战
查看>>
马斯克生日之际,特斯拉正式交付30辆顶配版Model 3
查看>>