Hessian是一個輕量級的remoting on http工具,采用的是Binary RPC協議,所以它很適合於發送二進制數據,同時又具有防火牆穿透能力。Hessian一般是通過Web應用來提供服務,因此非常類似於平時我們用的WebService。只是它不使用SOAP協議,但相比webservice而言更簡單、快捷。
Hessian官網:http://hessian.caucho.com/
Hessian可通過Servlet提供遠程服務,需要將匹配某個模式的請求映射到Hessian服務。也可Spring框架整合,通過它的DispatcherServlet可以完成該功能,DispatcherServlet可將匹配模式的請求轉發到Hessian服務。Hessian的server端提供一個servlet基類, 用來處理發送的請求,而Hessian的這個遠程過程調用,完全使用動態代理來實現的,,建議采用面向接口編程,Hessian服務通過接口暴露。
Hessian處理過程示意圖:
客戶端——>序列化寫到輸出流——>遠程方法(服務器端)——>序列化寫到輸出流 ——>客戶端讀取輸入流——>輸出結果
下面詳細介紹最常用的兩種方式實現Hessian提供webservice:
純Hessian實現
配合Spring框架實現
在開始之前當然需要到官網上下載相關的lib包,放入項目的/WEB-INF/lib/下
【一】、純Hessian實現步驟:
1.基本代碼
首先編寫一個服務的接口類:HelloHessian.Java
Java代碼
- package michael.hessian;
- import Java.util.List;
- import Java.util.Map;
- /**
- * @author michael
- *
- */
- public interface HelloHessian {
- String sayHello();
- MyCar getMyCar();
- List
myLoveFruit(); - Map
myBabays(); - }
一個java bean文件MyCar.Java:
Java代碼
- package michael.hessian;
- import Java.io.Serializable;
- /**
- * @author michael
- *
- */
- public class MyCar implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 4736905401908455439L;
- private String carName;
- private String carModel;
- /**
- * @return the carName
- */
- public String getCarName() {
- return carName;
- }
- /**
- * @return the carModel
- */
- public String getCarModel() {
- return carModel;
- }
- /**
- * @param pCarName the carName to set
- */
- public void setCarName(String pCarName) {
- carName = pCarName;
- }
- /**
- * @param pCarModel the carModel to set
- */
- public void setCarModel(String pCarModel) {
- carModel = pCarModel;
- }
- /**
- * @see Java.lang.Object#toString()
- * @return
- */
- @Override
- public String toString() {
- return "my car name:[" + this.carName + "] model:[" + this.carModel
- + "].";
- }
- }
服務端接口的實現類:HelloHessianImpl.Java
Java代碼
- package michael.hessian.impl;
- import Java.util.ArrayList;
- import Java.util.HashMap;
- import Java.util.List;
- import Java.util.Map;
- import michael.hessian.HelloHessian;
- import michael.hessian.MyCar;
- /**
- * @author michael
- *
- */
- public class HelloHessianImpl extends HessianServlet implements HelloHessian {
- public MyCar getMyCar() {
- MyCar car = new MyCar();
- car.setCarName("阿斯頓·馬丁");
- car.setCarModel("One-77");
- return car;
- }
- public Map
myBabays() { - Map
map = new HashMap (); - map.put("son", "孫吳空");
- map.put("daughter", "孫小美");
- return map;
- }
- public List
myLoveFruit() { - List
list = new ArrayList (); - list.add("apple");
- list.add("kiwi");
- list.add("orange");
- return list;
- }
- public String sayHello() {
- return "welcom to Hessian";
- }
- }
2.配置文件web.XML修改
在web.XML配置文件裡增加如下信息:
XML代碼
- <servlet>
- <servlet-name>HelloHessian< span>servlet-name>
- <servlet-class>
- com.caucho.hessian.server.HessianServlet
- < span>servlet-class>
- <init-param>
- <param-name>home-class< span>param-name>
- <param-value>michael.hessian.impl.HelloHessianImpl< span>param-value>
- < span>init-param>
- <init-param>
- <param-name>home-api< span>param-name>
- <param-value>michael.hessian.HelloHessian< span>param-value>
- < span>init-param>
- <load-on-startup>1< span>load-on-startup>
- < span>servlet>
- <servlet-mapping>
- <servlet-name>HelloHessian< span>servlet-name>
- <url-pattern>/HessianService< span>url-pattern>
- < span>servlet-mapping>
- <servlet-mapping>
3.Java客戶端驗證
Java代碼
- package michael.hessian.clIEnt;
- import Java.Net.MalformedURLException;
- import Java.util.Map;
- import michael.hessian.HelloHessian;
- import michael.hessian.MyCar;
- import com.caucho.hessian.clIEnt.HessianProxyFactory;
- /**
- * @author michael
- *
- */
- public class HessianClIEntTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- String url = "http://localhost:8082/J2EE_sJSky/HessianService";
- HessianProxyFactory factory = new HessianProxyFactory();
- try {
- HelloHessian hello = (HelloHessian) factory.create(
- HelloHessian.class, url);
- System.out.println(hello.sayHello());
- MyCar car = hello.getMyCar();
- System.out.println(car.toString());
- for (Map.Entry
entry : hello.myBabays().entrySet()) { - System.out.println(entry.getKey() + " " + entry.getValue());
- }
- for (String str : hello.myLoveFruit()) {
- System.out.println(str);
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
- }
- }
運行結果如下:
Java代碼
- welcom to Hessian
- my car name:[阿斯頓·馬丁] model:[One-77].
- daughter 孫小美
- son 孫吳空
- apple
- kiwi
- orange
【二】、spring+hessian 實現服務端:
1.基本代碼見上面的demo
2.修改配置文件
在web.XML,增加內容如下:
XML代碼
- <servlet>
- <servlet-name>springhessian< span>servlet-name>
- <servlet-class>
- org.springframework.web.servlet.DispatcherServlet
- < span>servlet-class>
1 springhessian /springhessian/*
在/WEB-INF/增加一個叫servlet-name-servlet.xml配置文件。該文件的命名有一定的規則,紅色servlet-name需要和web.XML中的
當然該文件也可以自己任意命名。如果是自定義的文件名稱不符合上述默認的規則,需要在
范例:springhessian-servlet.XML
XML代碼
- class="michael.hessian.impl.HelloHessianImpl" />
- <bean name="/helloHessianService"
- class="org.springframework.remoting.caucho.HessianServiceExporter">
- <property name="service" ref="helloHessianImpl" />
- <property name="serviceInterface"
- value="michael.hessian.HelloHessian" />
- < span>bean>
- < span>beans>
3.Java客戶端驗證
和上面的例子相似,只需要把訪問的url替換成新的即可如下:
Java代碼
- String url=http://localhost:8082/J2EE_sJSky/springhessian/helloHessianService
運行結果和上面例子一樣。
4.spring配置客戶端
增加一個spring的bean配置文件hessian-clIEnt.XML
XML代碼
- >
- <beans>
- <bean id="helloHessianClIEnt"
- class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
- <property name="serviceUrl">
- <value>
- http://localhost:8082/J2EE_sJSky/springhessian/helloHessianService
- < span>value>
- < span>property>
- <property name="serviceInterface"
- value="michael.hessian.HelloHessian" />
- < span>bean>
- < span>beans>
測試代碼HessianSpringClIEnt.Java:
Java代碼
- package michael.hessian.clIEnt;
- import Java.util.Map;
- import michael.hessian.HelloHessian;
- import michael.hessian.MyCar;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXMLApplicationContext;
- /**
- * @author michael
- *
- */
- public class HessianSpringClIEnt {
- /**
- * @param args
- */
- public static void main(String[] args) {
- try {
- ApplicationContext context = new ClassPathXMLApplicationContext(
- "hessian-clIEnt.XML");
- HelloHessian hello = (HelloHessian) context
- .getBean("helloHessianClIEnt");
- System.out.println(hello.sayHello());
- MyCar car = hello.getMyCar();
- System.out.println(car.toString());
- for (Map.Entry
entry : hello.myBabays().entrySet()) { - System.out.println(entry.getKey() + " " + entry.getValue());
- }
- for (String str : hello.myLoveFruit()) {
- System.out.println(str);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
運行結果和上面完全一致。
5.com.caucho.hessian.io.HessianProtocolException: expected string at 0x6d異常處理
我在spring+hessian整合測試過程中,客戶端調用時,發生了異常,而服務端錯誤內容如下:
Java代碼
- 2011-4-25 16:14:44 org.apache.catalina.core.StandardWrapperValve invoke
- 嚴重: Servlet.service() for servlet remoting threw exception
- com.caucho.hessian.io.HessianProtocolException: expected string at 0x6d
- at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.Java:2882)
- at com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.Java:2830)
- at com.caucho.hessian.io.Hessian2Input.readString(Hessian2Input.Java:1362)
- at com.caucho.hessian.io.Hessian2Input.readMethod(Hessian2Input.Java:272)
- at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.Java:249)
- at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.Java:221)
- at org.springframework.remoting.caucho.Hessian2SkeletonInvoker.invoke(Hessian2SkeletonInvoker.Java:67)
- at org.springframework.remoting.caucho.HessianServiceExporter.handleRequest(HessianServiceExporter.Java:147)
- at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.Java:49)
- at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:819)
- at org.springframework.web.servlet.DispatcherServlet.DOService(DispatcherServlet.Java:754)
- at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:399)
- at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.Java:364)
- at javax.servlet.http.HttpServlet.service(HttpServlet.Java:710)
- at javax.servlet.http.HttpServlet.service(HttpServlet.Java:803)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:290)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:206)
- at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:230)
- at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:175)
- at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:128)
- at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:104)
- at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:109)
- at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:261)
- at org.apache.coyote.http11.Http11Processor.process(Http11Processor.Java:844)
- at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.Java:581)
- at org.apache.tomcat.util.Net.JIoEndpoint$Worker.run(JIoEndpoint.Java:447)
- at java.lang.Thread.run(Thread.Java:619)