Hessian源码学习(1)
来源:互联网 发布:知乎led灯化妆镜 编辑:程序博客网 时间:2024/06/02 22:34
HessianServlet 是一个非常普通的Servlet 它直接继承 GenericServlet
我们看其中两个核心方法:init与service方法(参考源码版本3.0.13)
init(ServletConfig config)
该方法覆写父类的init(ServletConfig config)方法(按照servlet规范推荐,覆写init()方法更好)
在初始化中,它做了哪些事情呢?
第一步.初始化远程服务类(Impl)
其中home-class或者service-class就是在web.xml配置的提供远程服务的类(两者取一个作为配置即可);
它首先通过getInitParameter方法获取类名,然后调用loadClass获取对应的Class,最后newInstance创建实例;
若用户未配置,使用当前Servlet作为默认实现类(不能为HessianServlet);
我们接着往下看:init(_homeImpl) 又做了些什么呢?
根据当前服务类(impl)继承的接口(可以是标准的servlet接口也可以是Hessian中定义的Service接口)做相应的初始化(相当于spring的init标签属性);
第二步.初始化远程服务类接口(基本上Hessian也是通过这接口知道自己对外暴露了哪些服务)
其中home-api或是api-class定义了对外暴露的服务接口(服务的使用方需要依赖这个接口jar包);
若在配置文件中未指定接口,首先尝试从当前服务类查找(findRemoteAPI);
findRemoteAPI是一个递归方法:在类继承路径上递归查找只继承一个接口的类
若查找失败,则使用当前服务类作为interface Class(这句话说得很奇怪,还是看代码比较明了)
第三步.初始化 HessianSkeleton 类(相当于HessianExecutor)
重点在于super(apiClass):AbstractSkeleton的初始化
Method []methodList = apiClass.getMethods();
获取服务接口中(_homeAPI)所有public方法,这也是为什么hessian说:每一个public方法都是一个远程服务。
接着遍历所有方法,放入_methodMap中,这里有个关键点,如何支持重载?
Hessian是这样处理的,比如对于一个方法: public void sayHello(String str),那么在_methodMap中会存放三个key(这三个key对应着同一个value,也就是sayHello方法)
sayHello
sayHello_1 (参数个数)
sayHello_string (参数类型)
所以只要client传递方法说明支持调用重载方法,那么他就会调用到正确的重载方法,不然结果是不确定的。
service(ServletRequest request, ServletResponse response)
这个方法重写了父类(GenericServlet)的service方法
第一步.检查请求方式是否是post
第二步.初始化Hessian输入流/输出流
第三步.调用服务(这就是RPC中的C哈 ^_^)
我们具体看下HessianSkeleton.invoke方法:
HessianServlet总结
通过上面的源码分析,我们了解到:
1.Hessian如何响应一个远程调用;
2.在web.xml中的各项配置都是什么意思,以及Hessian相应的默认处理规则;
3.Hessian如何支持方法重载;
我们看其中两个核心方法:init与service方法(参考源码版本3.0.13)
init(ServletConfig config)
该方法覆写父类的init(ServletConfig config)方法(按照servlet规范推荐,覆写init()方法更好)
在初始化中,它做了哪些事情呢?
第一步.初始化远程服务类(Impl)
Java代码
- if (_homeImpl != null) {
- }
- else if (getInitParameter("home-class") != null) {
- String className = getInitParameter("home-class");
- Class homeClass = loadClass(className);
- _homeImpl = homeClass.newInstance();
- init(_homeImpl);
- }
- 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;
- }
其中home-class或者service-class就是在web.xml配置的提供远程服务的类(两者取一个作为配置即可);
它首先通过getInitParameter方法获取类名,然后调用loadClass获取对应的Class,最后newInstance创建实例;
若用户未配置,使用当前Servlet作为默认实现类(不能为HessianServlet);
我们接着往下看:init(_homeImpl) 又做了些什么呢?
Java代码
- private void init(Object service)
- throws ServletException
- {
- if (service instanceof Service)
- ((Service) service).init(getServletConfig());
- else if (service instanceof Servlet)
- ((Servlet) service).init(getServletConfig());
- }
根据当前服务类(impl)继承的接口(可以是标准的servlet接口也可以是Hessian中定义的Service接口)做相应的初始化(相当于spring的init标签属性);
第二步.初始化远程服务类接口(基本上Hessian也是通过这接口知道自己对外暴露了哪些服务)
Java代码
- 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) {
- _homeAPI = findRemoteAPI(_homeImpl.getClass());
- if (_homeAPI == null)
- _homeAPI = _homeImpl.getClass();
- }
- }
其中home-api或是api-class定义了对外暴露的服务接口(服务的使用方需要依赖这个接口jar包);
若在配置文件中未指定接口,首先尝试从当前服务类查找(findRemoteAPI);
findRemoteAPI是一个递归方法:在类继承路径上递归查找只继承一个接口的类
Java代码
- private Class findRemoteAPI(Class implClass)
- {
- if (implClass == null || implClass.equals(GenericService.class))
- return null;
- Class []interfaces = implClass.getInterfaces();
- if (interfaces.length == 1)
- return interfaces[0];
- return findRemoteAPI(implClass.getSuperclass());
- }
若查找失败,则使用当前服务类作为interface Class(这句话说得很奇怪,还是看代码比较明了)
第三步.初始化 HessianSkeleton 类(相当于HessianExecutor)
Java代码
- public HessianSkeleton(Object service, Class apiClass)
- {
- super(apiClass);
- _service = service;
- if (! apiClass.isAssignableFrom(service.getClass()))
- throw new IllegalArgumentException("Service " + service + " must be an instance of " + apiClass.getName());
- }
重点在于super(apiClass):AbstractSkeleton的初始化
Java代码
- protected AbstractSkeleton(Class apiClass)
- {
- _apiClass = apiClass;
- Method []methodList = apiClass.getMethods();
- for (int i = 0; i < methodList.length; i++) {
- Method method = methodList[i];
- if (_methodMap.get(method.getName()) == null)
- _methodMap.put(method.getName(), methodList[i]);
- Class []param = method.getParameterTypes();
- String mangledName = method.getName() + "__" + param.length;
- _methodMap.put(mangledName, methodList[i]);
- _methodMap.put(mangleName(method, false), methodList[i]);
- }
- }
Method []methodList = apiClass.getMethods();
获取服务接口中(_homeAPI)所有public方法,这也是为什么hessian说:每一个public方法都是一个远程服务。
接着遍历所有方法,放入_methodMap中,这里有个关键点,如何支持重载?
Hessian是这样处理的,比如对于一个方法: public void sayHello(String str),那么在_methodMap中会存放三个key(这三个key对应着同一个value,也就是sayHello方法)
sayHello
sayHello_1 (参数个数)
sayHello_string (参数类型)
所以只要client传递方法说明支持调用重载方法,那么他就会调用到正确的重载方法,不然结果是不确定的。
service(ServletRequest request, ServletResponse response)
这个方法重写了父类(GenericServlet)的service方法
第一步.检查请求方式是否是post
Java代码
- if (! req.getMethod().equals("POST")) {
- res.setStatus(500, "Hessian Requires POST");
- PrintWriter out = res.getWriter();
- res.setContentType("text/html");
- out.println("<h1>Hessian Requires POST</h1>");
- return;
- }
第二步.初始化Hessian输入流/输出流
Java代码
- InputStream is = request.getInputStream();
- OutputStream os = response.getOutputStream();
- HessianInput in = new HessianInput(is);
- HessianOutput out = new HessianOutput();
- out.setSerializerFactory(getSerializerFactory()); // 关于这里的序列化工厂,后面的文章会详述
- out.init(os);
第三步.调用服务(这就是RPC中的C哈 ^_^)
Java代码
- _homeSkeleton.invoke(in, out);
我们具体看下HessianSkeleton.invoke方法:
Java代码
- //反序列化输入流获取调用的服务方法
- String methodName = in.readMethod();
- Method method = getMethod(methodName);
- //反序列输入流获取方法参数
- Class []args = method.getParameterTypes();
- Object []values = new Object[args.length];
- for (int i = 0; i < args.length; i++)
- values[i] = in.readObject(args[i]);
- // 真正的执行服务方法
- result = method.invoke(_service, values);
- //最后把执行写回输出流,输出起始标志:'r' 1 0
- out.startReply();
- // 序列化结果(远程调用结果)
- out.writeObject(result);
- // 输出结束标志'z'
- out.completeReply();
HessianServlet总结
通过上面的源码分析,我们了解到:
1.Hessian如何响应一个远程调用;
2.在web.xml中的各项配置都是什么意思,以及Hessian相应的默认处理规则;
3.Hessian如何支持方法重载;
0 0
- Hessian源码学习(1)
- Hessian源码学习(2)
- 学习Hessian-1
- Hessian学习(1)
- 【Hessian】hessian学习
- hessian源码,com.caucho.hessian
- hessian学习
- hessian学习
- hessian学习
- Hessian学习
- Hessian学习
- Hessian学习
- Hessian学习
- Hessian学习
- hessian学习
- hessian学习
- hessian学习
- hessian学习
- Posts Tagged 【Math】
- Linux 目录结构说明
- 涉足计算机视觉领域要知道的
- 探讨在项目中如何处理错误信息
- 矩阵链相乘(递归、动态规划解法)
- Hessian源码学习(1)
- hznu 1652 能量项链(dp,难)
- LeetCode 169 Majority Element
- 如何查看网站的访问量?查看访问量的二个主要方法【站长之家的SEO综合查询工具】
- exit(0)与exit(1)、return区别
- Step into Scala - 01 - 安装与运行
- OJ 删数问题
- 计算机网络基础
- 安卓下载保存到本地(一)