Hessian源码剖析(七)

本篇博客我们来看一下Hessian的server端是如何实现的,首先来看一下Server端Hessian的配置

        下面是web.xml中的一段配置(web.xml文件是web应用特有的文件,Hessian的server端需要集成在web应用下,如果想在非web应用中使用Hessian的server端需要在Hessian的基础上进行二次开发),servlet和servlet-mapping的映射关系是通过servlet-name对应起来的,/servive/remote路径下的Http请求会映射到HessianServlet上,这些是servlet规范,凡是支持servlet规范的web容器都要符合这样的规范(例如tomcat),但是每个具体的容器的实现可以不同,在规范中每个自定义的servlet一定要实现Servlet接口并实现doGet和doPost方法才可以

但是我们知道servet端的Hessian的并不需要实现Servlet接口,那这又是为什么呢?

因为Hessian替我们做了这些事情,Hessian把servlet相关的细节封装了起来,下面来看一下Hessian是如何封装的

以下面的/service/remote  为例,这个路径下面的Http请求会对应到HessianServlet中,第一次请求会执行HessianServlet的init()方法

	<servlet>
		<servlet-name>remote-service</servlet-name>
		<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
		<init-param>
			<param-name>home-class</param-name>
			<param-value>com.kong.serviceimpl.HessianHelloWorldImpl</param-value>
		</init-param>
	</servlet>

	<servlet-mapping>
		<servlet-name>remote-service</servlet-name>
		<url-pattern>/service/remote</url-pattern>
	</servlet-mapping>
HessianServlet的init()方法较长,我们只看一下重点的代码

            if (_homeImpl != null) {
            }
            //getInitParameter()方法是用来获取web.xml配置中servlet标签下init-param标签中的内容,这是servlet-api.jar里面提供的一个方法
           else if (getInitParameter("home-class") != null) {
                String className = getInitParameter("home-class");
                //加载<param-value>标签中的类到内存中
                Class homeClass = loadClass(className);//代码2
                //创建该类的实例
                _homeImpl = homeClass.newInstance();//代码3
                //如果我们自定义的类实现了Servlet接口或者Service接口(这两个接口都是servlet-api中的接口),那么调用类的init()方法
                init(_homeImpl);//代码4
            }
             //service-class和home-class的功能是完全一样的
            else if (getInitParameter("service-class") != null) {
                String className = getInitParameter("service-class");

                Class homeClass = loadClass(className);

                _homeImpl = homeClass.newInstance();

                init(_homeImpl);
            } else {
                if (getClass().equals(HessianServlet.class))
                    throw new ServletException("server must extend HessianServlet");

                _homeImpl = this;
            }

            if (_homeAPI != null) {
            } else if (getInitParameter("home-api") != null) {
                String className = getInitParameter("home-api");

                _homeAPI = loadClass(className);
            } else if (getInitParameter("api-class") != null) {
                String className = getInitParameter("api-class");

                _homeAPI = loadClass(className);
            } else if (_homeImpl != null) {
                //findRemoteAPI()方法负责找到_homeImpl实现的接口,
               _homeAPI = findRemoteAPI(_homeImpl.getClass());

                if (_homeAPI == null)
                    _homeAPI = _homeImpl.getClass();
            }
            
            if (_objectImpl != null) {
            } else if (getInitParameter("object-class") != null) {
                String className = getInitParameter("object-class");

                Class objectClass = loadClass(className);

                _objectImpl = objectClass.newInstance();

                init(_objectImpl);
            }

            if (_objectAPI != null) {
            } else if (getInitParameter("object-api") != null) {
                String className = getInitParameter("object-api");

                _objectAPI = loadClass(className);
            } else if (_objectImpl != null)
                _objectAPI = _objectImpl.getClass();
            //创建HessianSkeleton实例,该实例用来处理对应的HTTP请求,并解析请求将请求打到对应的类上
            _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI);



HessianServlet的init()方法只会在第一次初始化时执行一次,执行完init()方法后会执行HessianServlet的service()方法而service()方法会调用HessianServlet的HessianSkeleton的invoke()方法,HessianSkeleton对象是在执行HessianServlet的init()方法时创建的

invoke()方法如下

 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",
                     "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",
                     "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
   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", 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();
  }
===============到此为止,Hessian的一个rpc调用就全部结束了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值