【服务端】
HessianServlet 是一个非常普通的Servlet 它直接继承 GenericServlet
我们看其中两个核心方法:init与service方法(参考源码版本3.0.13)
init(ServletConfig config)
该方法覆写父类的init(ServletConfig config)方法(按照servlet规范推荐,覆写init()方法更好)
在初始化中,它做了哪些事情呢?
第一步.初始化远程服务类(Impl)
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) 又做了些什么呢?
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也是通过这接口知道自己对外暴露了哪些服务)
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是一个递归方法:在类继承路径上递归查找只继承一个接口的类
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)
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的初始化
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
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输入流/输出流
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哈 ^_^)
_homeSkeleton.invoke(in, out);
我们具体看下HessianSkeleton.invoke方法:
//反序列化输入流获取调用的服务方法
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如何支持方法重载;
在下一篇文章中,我们将会分析客户端如何调用Hessian服务!欢迎朋友们提出宝贵意见!
分享到:
相关推荐
至于标签"源码",学习Hessian时查看源码有助于理解其内部工作原理,比如数据如何被编码和解码。你可以通过阅读开源的Hessian库,如Caucho Hessian的Java实现,来了解其底层细节。 至于"工具",有一些工具可以帮助...
10. **源码阅读**:对于深入理解Hessian的工作原理,阅读源码是一个很好的学习途径。通过查看源码,可以理解数据如何被序列化和反序列化,以及如何处理远程调用的细节。 综上所述,学习Hessian需要掌握二进制序列化...
在博客链接《iteye博客:550771》中,作者可能详细讨论了Hessian的使用方法、优缺点以及实战案例,可以作为学习Hessian的参考资料。 **六、Hessian的使用场景** 1. **微服务通信**:在微服务架构中,Hessian可以...
总之,这个"PHP与Java通信Demo源码"是一个很好的学习资源,帮助开发者理解如何在PHP和Java之间使用Hessian协议进行通信。通过分析和实践这些示例代码,你可以更好地掌握Hessian的工作原理和使用方式,为你的跨语言...
《深入解析Hessian 4.0.51源码》 Hessian,作为一个高效轻量级的二进制Web服务协议,广泛应用于分布式系统中,它允许开发者...对于想深入理解分布式通信机制的开发者来说,研究Hessian源码无疑是一次宝贵的学习机会。
2. Hessian的安全策略:学习如何在Hessian服务上实现认证和授权,防止未授权访问。 3. 性能优化:通过调整Hessian配置,如连接池大小、超时时间等,来提升服务性能。 4. 异常处理:研究如何处理Hessian通信过程中的...
在Spring框架中集成Hessian是为了实现远程方法调用(Remote Method Invocation, RMI),这是一种轻量级的序列化协议,可以高效地传输Java...通过深入学习和实践,我们可以更好地利用Hessian来构建高性能的分布式系统。
2. **示例代码**:这些示例可以帮助我们理解如何在实际项目中使用Hessian,包括创建服务端、客户端,以及调用远程服务的方法。 3. **测试用例**:源代码可能包含单元测试和集成测试,通过这些测试,我们可以验证...
标题中的“spring整合hessian进行远程通讯”是指在Spring框架中使用Hessian库来实现远程过程调用(RPC)。...在实际开发中,我们需要结合源码学习,了解其实现原理,并注意安全性和性能优化,确保系统的稳定运行。
Java Hessian小试(转) Java Hessian是一种二进制的RPC(远程过程调用)协议,由Caucho...在压缩包子文件"**Hessian**"中,可能包含了一些示例代码或者Hessian的实现细节,对于学习和研究Hessian的源码有一定的帮助。
这个jar文件可以被Java应用程序引入,以便在客户端和服务端之间进行Hessian协议的通信。它包括了序列化和反序列化机制,以及对HTTP和HTTPS的支持,使得远程方法调用变得简单且高效。 `hessian-4.0.7-src.jar`则是...
**Hessian入门介绍** 在IT领域,Hessian是一种二进制Web服务协议,它由Caucho Technology开发,主要用于提供...通过学习和实践`HessianDemo`,开发者能够掌握Hessian的基本用法,从而在实际项目中有效地利用这一工具。
通过阅读这个博客,我们可以学习到如何在实际项目中应用Hessian协议,以及如何优化自定义实现。 标签 "源码" 和 "工具" 提醒我们,这个项目不仅涉及理论知识,还包含了实际的代码实现,可能是一个工具或者库,可以...
Flex是Adobe开发的一种开放源码的富互联网应用(RIA)开发框架,用于创建交互性强、用户体验良好的Web应用程序。Hessian是一种二进制Web服务协议,它提供了轻量级、高效的远程方法调用(RPC)机制,尤其适合于Java和...
2. **Hessian服务端集成**:在服务器端,开发者需要配置Hessian服务,这通常涉及到创建Java服务接口和实现。Hessian库将这些Java对象暴露为二进制HTTP服务,使得Flex客户端可以调用。 3. **Hessian客户端API**:在...
3. 掌握如何通过Hessian源码调试和优化性能。 4. 熟悉Hessian与其他通信协议(如HTTP、SOAP)的对比,以便根据项目需求选择最佳方案。 总结,Hessian 4.0.7是一个强大的工具,尤其适合需要高效远程调用的Java开发者...
3. **源码分析**: 深入理解Hessian源码对于优化和定制Hessian服务非常重要。源码可能包含了Hessian序列化和反序列化的实现细节,以及处理异常和错误的方式。通过阅读源码,你可以了解到Hessian如何处理不同类型的...
在实际开发中,使用Eclipse或MyEclipse这样的IDE可以帮助开发者方便地管理Hessian服务,通过配置`.classpath`和`.project`文件来导入所需的库,如Hessian的客户端和服务端API。`src`目录下的源代码可能包含了使用...