- 浏览: 319242 次
- 性别:
- 来自: 济南
文章分类
- 全部博客 (221)
- J2SE心得 (4)
- 经典帖子 (8)
- 亲身经历 (9)
- SSH框架 (12)
- 数据库 (10)
- java基础知识 (41)
- java解惑 (17)
- 软件测试 (0)
- JSP (6)
- JavaScript (8)
- jQuery学习 (12)
- 硬件知识 (1)
- 工具类 (14)
- 面试专题 (4)
- Struts2专题(学习) (14)
- Spring源码分析专题(学习) (15)
- JavaScript专题(学习) (8)
- ExtJs专题(学习) (6)
- Java Web快速入门——全十讲 (10)
- web前台 (1)
- J2ME手机方面 (1)
- 积累整理 (1)
- MyEclipse工具篇 (10)
- oracle (1)
- Android基础 (1)
最新评论
-
youjianbo_han_87:
上传成功后,无法跳转到success页面,会报2038和404 ...
Struts2使用FlashFileUpload.swf实现批量文件上传 -
showzh:
...
MyEclipse 怎么安装SVN插件 -
wpf523:
赞一个啊,楼主加油
一些比较复杂的运算符(二) -
独步天下:
request.getSession().getAttribute() 和request.getSession().setAttribute() -
HelloJava1234:
thank you
怎么改变MyEclipse默认的jsp打开方式
项目选定Hessian作为web service的实现方式,确实很轻量级,速度就跟直接用socket差不多,全是二进制传送节约了不少开销。但是在使用过程中有业务需要是必须获得远程端的ip地址,主机名等信息的。翻便Hessian的文档和google了n次未果,迫不得已到caucho和spring论坛去问,都没有得到答复。今天心一横把hessian的源代码加入到项目中单步跟踪,总算有点小收获。献丑分享出来,一方面给需要的朋友,主要还是希望各位找找是否存在bug,以及是否有更好的改良。
一:先撇开Spring不谈,来看看纯Hessian的调用
按照hessian文档里边介绍的demo,在web.xml里边如下配置
- <servlet>
- <servlet-name>hello</servlet-name>
- <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
- <init-param>
- <param-name>home-class</param-name>
- <param-value>example.BasicService</param-value>
- </init-param>
- <init-param>
- <param-name>home-api</param-name>
- <param-value>example.Basic</param-value>
- </init-param>
- </servlet>
- <servlet-mapping>
- <url-pattern>/hello</url-pattern>
- <servlet-name>hello</servlet-name>
- </servlet-mapping>
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <param-name>home-class</param-name> <param-value>example.BasicService</param-value> </init-param> <init-param> <param-name>home-api</param-name> <param-value>example.Basic</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/hello</url-pattern> <servlet-name>hello</servlet-name> </servlet-mapping>
由此可知Hessian调用的入口是HessianServlet这个Servlet,进去看看
- /**
- * Servlet for serving Hessian services.
- */
- public class HessianServlet extends GenericServlet {
- private Class _homeAPI;
- private Object _homeImpl;
- private Class _objectAPI;
- private Object _objectImpl;
- private HessianSkeleton _homeSkeleton;
- private HessianSkeleton _objectSkeleton;
- private SerializerFactory _serializerFactory;
- public String getServletInfo()
- {
- return "Hessian Servlet";
- }
- /**
- * Sets the home api.
- */
- public void setHomeAPI(Class api)
- {
- _homeAPI = api;
- }
- /**
- * Sets the home implementation
- */
- public void setHome(Object home)
- {
- _homeImpl = home;
- }
- /**
- * Sets the object api.
- */
- public void setObjectAPI(Class api)
- {
- _objectAPI = api;
- }
- /**
- * Sets the object implementation
- */
- public void setObject(Object object)
- {
- _objectImpl = object;
- }
- /**
- * Sets the service class.
- */
- public void setService(Object service)
- {
- setHome(service);
- }
- /**
- * Sets the api-class.
- */
- public void setAPIClass(Class api)
- {
- setHomeAPI(api);
- }
- /**
- * Gets the api-class.
- */
- public Class getAPIClass()
- {
- return _homeAPI;
- }
- /**
- * Sets the serializer factory.
- */
- public void setSerializerFactory(SerializerFactory factory)
- {
- _serializerFactory = factory;
- }
- /**
- * Gets the serializer factory.
- */
- public SerializerFactory getSerializerFactory()
- {
- if (_serializerFactory == null)
- _serializerFactory = new SerializerFactory();
- return _serializerFactory;
- }
- /**
- * Sets the serializer send collection java type.
- */
- public void setSendCollectionType(boolean sendType)
- {
- getSerializerFactory().setSendCollectionType(sendType);
- }
- /**
- * Initialize the service, including the service object.
- */
- public void init(ServletConfig config)
- throws ServletException
- {
- super.init(config);
- try {
- 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;
- }
- 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();
- }
- 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();
- _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI);
- if (_objectAPI != null)
- _homeSkeleton.setObjectClass(_objectAPI);
- if (_objectImpl != null) {
- _objectSkeleton = new HessianSkeleton(_objectImpl, _objectAPI);
- _objectSkeleton.setHomeClass(_homeAPI);
- }
- else
- _objectSkeleton = _homeSkeleton;
- } catch (ServletException e) {
- throw e;
- } catch (Exception e) {
- throw new ServletException(e);
- }
- }
- 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());
- }
- private Class loadClass(String className)
- throws ClassNotFoundException
- {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if (loader != null)
- return Class.forName(className, false, loader);
- else
- return Class.forName(className);
- }
- private void init(Object service)
- throws ServletException
- {
- if (service instanceof Service)
- ((Service) service).init(getServletConfig());
- else if (service instanceof Servlet)
- ((Servlet) service).init(getServletConfig());
- }
- /**
- * Execute a request. The path-info of the request selects the bean.
- * Once the bean's selected, it will be applied.
- */
- public void service(ServletRequest request, ServletResponse response)
- throws IOException, ServletException
- {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpServletResponse res = (HttpServletResponse) response;
- 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;
- }
- String serviceId = req.getPathInfo();
- String objectId = req.getParameter("id");
- if (objectId == null)
- objectId = req.getParameter("ejbid");
- ServiceContext.begin(req, serviceId, objectId);
- try {
- InputStream is = request.getInputStream();
- OutputStream os = response.getOutputStream();
- Hessian2Input in = new Hessian2Input(is);
- AbstractHessianOutput out;
- SerializerFactory serializerFactory = getSerializerFactory();
- in.setSerializerFactory(serializerFactory);
- int code = in.read();
- if (code != 'c') {
- // XXX: deflate
- throw new IOException("expected 'c' in hessian input at " + code);
- }
- int major = in.read();
- int minor = in.read();
- if (major >= 2)
- out = new Hessian2Output(os);
- else
- out = new HessianOutput(os);
- out.setSerializerFactory(serializerFactory);
- if (objectId != null)
- _objectSkeleton.invoke(in, out);
- else
- _homeSkeleton.invoke(in, out);
- out.close();
- } catch (RuntimeException e) {
- throw e;
- } catch (ServletException e) {
- throw e;
- } catch (Throwable e) {
- throw new ServletException(e);
- } finally {
- ServiceContext.end();
- }
- }
- }
/** * Servlet for serving Hessian services. */ public class HessianServlet extends GenericServlet { private Class _homeAPI; private Object _homeImpl; private Class _objectAPI; private Object _objectImpl; private HessianSkeleton _homeSkeleton; private HessianSkeleton _objectSkeleton; private SerializerFactory _serializerFactory; public String getServletInfo() { return "Hessian Servlet"; } /** * Sets the home api. */ public void setHomeAPI(Class api) { _homeAPI = api; } /** * Sets the home implementation */ public void setHome(Object home) { _homeImpl = home; } /** * Sets the object api. */ public void setObjectAPI(Class api) { _objectAPI = api; } /** * Sets the object implementation */ public void setObject(Object object) { _objectImpl = object; } /** * Sets the service class. */ public void setService(Object service) { setHome(service); } /** * Sets the api-class. */ public void setAPIClass(Class api) { setHomeAPI(api); } /** * Gets the api-class. */ public Class getAPIClass() { return _homeAPI; } /** * Sets the serializer factory. */ public void setSerializerFactory(SerializerFactory factory) { _serializerFactory = factory; } /** * Gets the serializer factory. */ public SerializerFactory getSerializerFactory() { if (_serializerFactory == null) _serializerFactory = new SerializerFactory(); return _serializerFactory; } /** * Sets the serializer send collection java type. */ public void setSendCollectionType(boolean sendType) { getSerializerFactory().setSendCollectionType(sendType); } /** * Initialize the service, including the service object. */ public void init(ServletConfig config) throws ServletException { super.init(config); try { 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; } 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(); } 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(); _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI); if (_objectAPI != null) _homeSkeleton.setObjectClass(_objectAPI); if (_objectImpl != null) { _objectSkeleton = new HessianSkeleton(_objectImpl, _objectAPI); _objectSkeleton.setHomeClass(_homeAPI); } else _objectSkeleton = _homeSkeleton; } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException(e); } } 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()); } private Class loadClass(String className) throws ClassNotFoundException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) return Class.forName(className, false, loader); else return Class.forName(className); } private void init(Object service) throws ServletException { if (service instanceof Service) ((Service) service).init(getServletConfig()); else if (service instanceof Servlet) ((Servlet) service).init(getServletConfig()); } /** * Execute a request. The path-info of the request selects the bean. * Once the bean's selected, it will be applied. */ public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; 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; } String serviceId = req.getPathInfo(); String objectId = req.getParameter("id"); if (objectId == null) objectId = req.getParameter("ejbid"); ServiceContext.begin(req, serviceId, objectId); try { InputStream is = request.getInputStream(); OutputStream os = response.getOutputStream(); Hessian2Input in = new Hessian2Input(is); AbstractHessianOutput out; SerializerFactory serializerFactory = getSerializerFactory(); in.setSerializerFactory(serializerFactory); int code = in.read(); if (code != 'c') { // XXX: deflate throw new IOException("expected 'c' in hessian input at " + code); } int major = in.read(); int minor = in.read(); if (major >= 2) out = new Hessian2Output(os); else out = new HessianOutput(os); out.setSerializerFactory(serializerFactory); if (objectId != null) _objectSkeleton.invoke(in, out); else _homeSkeleton.invoke(in, out); out.close(); } catch (RuntimeException e) { throw e; } catch (ServletException e) { throw e; } catch (Throwable e) { throw new ServletException(e); } finally { ServiceContext.end(); } } }
先看init()函数,功能还是一样,初始话一些东西,读入init-param的内容,并且load这些init-param的class
主要的还是service()函数
在service函数里边会获得request和response对象的输入和输出流,用来构造Hessian2Input和Hessian2Output,Hessian就是解析这两个东西来执行函数调用的。当然,在service里边还有一个重要的语句
ServiceContext.begin(req, serviceId, objectId);
这个函数有点奇怪,我每次到这里serviceId和objectId都是空,不知道是不是历史遗留问题还存在这两个参数。
进去这个类看看
- public class ServiceContext {
- private static final ThreadLocal _localContext = new ThreadLocal();
- private ServletRequest _request;
- private String _serviceName;
- private String _objectId;
- private int _count;
- private HashMap _headers = new HashMap();
- private ServiceContext()
- {
- }
- /**
- * Sets the request object prior to calling the service's method.
- *
- * @param request the calling servlet request
- * @param serviceId the service identifier
- * @param objectId the object identifier
- */
- public static void begin(ServletRequest request,
- String serviceName,
- String objectId)
- throws ServletException
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context == null) {
- context = new ServiceContext();
- _localContext.set(context);
- }
- context._request = request;
- context._serviceName = serviceName;
- context._objectId = objectId;
- context._count++;
- }
- /**
- * Returns the service request.
- */
- public static ServiceContext getContext()
- {
- return (ServiceContext) _localContext.get();
- }
- /**
- * Adds a header.
- */
- public void addHeader(String header, Object value)
- {
- _headers.put(header, value);
- }
- /**
- * Gets a header.
- */
- public Object getHeader(String header)
- {
- return _headers.get(header);
- }
- /**
- * Gets a header from the context.
- */
- public static Object getContextHeader(String header)
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context != null)
- return context.getHeader(header);
- else
- return null;
- }
- /**
- * Returns the service request.
- */
- public static ServletRequest getContextRequest()
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context != null)
- return context._request;
- else
- return null;
- }
- /**
- * Returns the service id, corresponding to the pathInfo of the URL.
- */
- public static String getContextServiceName()
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context != null)
- return context._serviceName;
- else
- return null;
- }
- /**
- * Returns the object id, corresponding to the ?id= of the URL.
- */
- public static String getContextObjectId()
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context != null)
- return context._objectId;
- else
- return null;
- }
- /**
- * Cleanup at the end of a request.
- */
- public static void end()
- {
- ServiceContext context = (ServiceContext) _localContext.get();
- if (context != null && --context._count == 0) {
- context._request = null;
- context._headers.clear();
- }
- }
- /**
- * Returns the service request.
- *
- * @deprecated
- */
- public static ServletRequest getRequest()
- {
- ServiceContext context = (ServiceContext) _localContext.get();
-
if (context != null)
</li
发表评论
-
Spring源代码解析(十):Spring Acegi框架授权的实现
2009-12-01 11:05 1334我们从FilterSecurityIntercep ... -
Spring源代码解析(九):Spring Acegi框架鉴权的实现
2009-12-01 11:04 1176简单分析一下Spring Acegi的源代码实现: Servl ... -
Spring源代码解析(八):Spring驱动Hibernate的实现
2009-12-01 11:03 1235O/R工具出现之后,简化了许多复杂的信息持久化的开发。Spri ... -
Spring源代码解析(七):Spring AOP中对拦截器调用的实现
2009-12-01 11:01 928前面我们分析了Spring AOP实现中得到Proxy对象的过 ... -
关于spring ioc容器的问题
2009-12-01 11:01 880在spring的源代码中,有org.springframewo ... -
Spring声明式事务管理源码解读之事务提交
2009-12-01 11:00 1054简介:上次说到spring声明式事务管理的事务开始部分,按流程 ... -
Spring源代码解析(六):Spring声明式事务处理
2009-12-01 11:00 1082我们看看Spring中的事务处理的代码,使用Spring管理事 ... -
Spring源代码解析(五):Spring AOP获取Proxy
2009-12-01 10:59 814下面我们来看看Spring的AOP的一些相关代码是怎么得到Pr ... -
Spring源代码解析(四):Spring MVC
2009-12-01 10:58 820下面我们对Spring MVC框架代码进行分析,对于webAp ... -
Spring声明式事务管理源码解读之事务开始
2009-12-01 10:57 707Spring声明式事务管理源码解读 简介:事务是所有企业应用系 ... -
Spring源代码解析(三):Spring JDBC
2009-12-01 10:56 1259下面我们看看Spring JDBC相关的实现, 在Spring ... -
Spring源代码解析(二):IoC容器在Web容器中的启动
2009-12-01 10:56 1132上面我们分析了IOC容器本身的实现,下面我们看看在典型的web ... -
Spring源代码解析(一):IOC容器
2009-12-01 10:55 1068在认真学习Rod.Johnson的 ... -
spring源码分析-XmlBeanFactory导读
2009-12-01 10:54 1718源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的, ...
相关推荐
com.alibaba:hessian-lite:jar:3.2.1-fixed-2 hessian-lite hessian-lite-3.2.1-fixed-2.jar
《Hessian源码分析与Hack:携带远程调用端信息》 Hessian作为一种轻量级的RPC(远程过程调用)框架,因其高效、简洁的二进制协议,被广泛应用于构建Web服务。然而,在实际应用中,有时我们需要获取到远程调用端的IP...
赠送Maven依赖信息文件:hessian-4.0.63.pom; 包含翻译后的API文档:hessian-4.0.63-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:com.caucho:hessian:4.0.63; 标签:hessian、caucho、jar包、java、...
- **配置详解**:文档通常会包含如何配置Hessian服务端和客户端的详细步骤,例如设置服务器端的监听端口,客户端的连接参数等。 - **示例代码**:提供服务端和服务端的代码示例,展示如何创建、注册服务以及如何...
赠送Maven依赖信息文件:hessian-4.0.63.pom; 包含翻译后的API文档:hessian-4.0.63-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.caucho:hessian:4.0.63; 标签:hessian、caucho、jar包、java、中文文档;...
Hessian是一种高效的二进制序列化协议,常用于远程过程调用(RPC)和服务之间的通信。这个压缩包包含了Hessian的多个版本,分别是Hessian3.1.6、Hessian3.2.1以及Hessian4.0.7。每个版本都有其特定的功能改进和优化...
在解压的"**hessian-4.0.51-src**"源码包中,主要包含两个关键文件:"**pom.xml**"和"**src**"。 1. **pom.xml**:这是Maven项目的配置文件,定义了项目依赖、构建过程等信息。通过这个文件,我们可以看到Hessian ...
赠送jar包:hessian-3.3.6.jar 赠送原API文档:hessian-3.3.6-javadoc.jar 赠送源代码:hessian-3.3.6-sources.jar 包含翻译后的API文档:hessian-3.3.6-javadoc-API文档-中文(简体)-英语-对照版.zip 对应Maven...
在IT行业中,远程调用是一种常见的技术,使得客户端可以跨网络调用远程服务器上的方法,就像调用本地方法一样方便。Hessian是Apache项目下的一个轻量级的RPC(Remote Procedure Call,远程过程调用)框架,它提供了...
赠送Maven依赖信息文件:hessian-3.3.6.pom; 包含翻译后的API文档:hessian-3.3.6-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.alipay.sofa:hessian:3.3.6; 标签:sofa、hessian、alipay、jar包、java、...
hessian是一个轻量级的Java Remoting方案
Hessian是由Caucho Technology开发的一种二进制Web服务协议,它提供了对Java对象序列化和反序列化的支持,使得远程调用如同本地调用一样快速和简单。与传统的XML-RPC或SOAP相比,Hessian的序列化格式更为紧凑,因此...
Hessian是一种轻量级的二进制Web服务协议,它由Caucho Technology开发,用于提高远程调用的效率和速度。Hessian 4.0.7是该协议的一个版本,提供了一个Java库,允许开发者在Java应用之间进行高效的数据交换。这个版本...
java运行依赖jar包
在服务器端,通过HessianServlet来暴露这个服务,客户端则通过HessianProxyFactory来创建服务代理,从而能够调用远程服务的方法。这种简单设置可以让开发者快速理解Hessian的基本工作原理。 二、Hessian与Spring...
在这个专题中,我们将以hessian-4.0.33.jar为例,详细探讨Hessian框架的核心特性和使用方法。 一、Hessian协议简介 Hessian协议基于HTTP协议,但其数据传输采用二进制格式,这使得它在数据传输效率上远超基于文本...
1. **远程调用**:在Dubbo框架中,Hessian-lite用于实现服务调用的二进制序列化和反序列化,使得远程方法调用(RMI)更加高效。它将Java对象转换为二进制流,通过网络发送,然后在服务端反序列化回原来的对象,降低了...
【标题】"dubbo-hessian-lite" 是一个与阿里巴巴的著名开源远程调用框架 Dubbo 相关的组件。Dubbo 提供了多种序列化方式,其中之一就是 Hessian 序列化,而 hessian-lite 是 Dubbo 在编译时依赖的一个轻量级 Hessian...
Spring会自动创建代理对象,使得客户端可以通过这个代理对象调用远程服务的方法,就像调用本地对象一样。 3. **使用源码分析**: Hessian库提供了`HessianProxyFactoryBean`和`HessianServiceExporter`这两个关键...