聲明:該文章轉載自Spring整合Hessian訪問遠程服務,本人搬過來只是為了記錄下學習Hessian的過程,忘此博主理解,在此感謝,等本人有能力了再學一些原創的東東,本人實踐了下,hessianServer項目不是web project,由於較菜,花了一個下午才把java project轉換成為web project。
項目下載:
hessianServer:http://files.cnblogs.com/ontheroad_lee/hessianServer.rar
hessianClient:http://files.cnblogs.com/ontheroad_lee/hessianClient.rar
1.1 Hessian簡介
Hessian是一個輕量級的Web服務實現工具,它采用的是二進制協議,因此很適合發送二進制數據。它的一個基本原理就是把遠程服務對象以二進制的方式進行發送和接收。
1.2 整合
1.2.1 概述
對於Hessian而言,有服務端和客戶端,所以我們的整合也需要分服務端的整合和客戶端的整合。服務端的整合是通過SpringMVC進行的,而客戶端的整合則是通過Spring的bean進行的。
1.2.2 服務端整合
基於客戶端要調用服務端的遠程服務,所以我們先來談一下服務端的整合。Hessian的遠程服務是基於接口的,所以我們要作為遠程服務的實現類必須要實現一個接口。作為示例,這里我們建立一個叫hessianServer的web項目作為遠程服務的服務端,在這個項目中我們建立一個叫做UserService的接口:
然后建立一個它的實現類UserServiceImpl:
那么接下來我們要做的就是把UserServiceImpl作為一個遠程服務進行發布,以致客戶端能夠進行訪問。
首先我們需要在web.xml中配置一個SpringMVC的DispatcherServlet用於接收所有的Web服務請求,這里我們這樣配置:
<servlet> <servlet-name>hessianServer</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hessianServer</servlet-name> <url-pattern>/api/service/*</url-pattern> </servlet-mapping>
可以看到我們這個DispatcherServlet會處理url為“/api/service/*”的請求,通配符“*”就對應着我們的處理器映射。
接下來就是在SpringMVC的配置文件中利用Hessian來定義我們的遠程服務了,這是通過Spring提供的HessianServiceExporter來實現的。我們需要在SpringMVC的配置文件中定義一個類型為HessianServiceExporter的bean對象。該bean對象需要接收兩個屬性,一個是service屬性,用於關聯真正的service對象,另一個是serviceInterface屬性,用於指定當前的服務對應的接口。HessianServiceExporter實現了HttpRequestHandler接口,當我們請求某一個遠程服務的時候實際上請求的就是其對應的HessianServiceExporter對象,HessianServiceExporter會把請求的服務以二進制的方式返回給客戶端。這里我們在SpringMVC的配置文件中這樣定義:
<bean id="userService" class="com.tiantian.hessianserver.service.impl.UserServiceImpl" /> <bean name="/userService" class="org.springframework.remoting.caucho.HessianServiceExporter"> <property name="service" ref="userService" /> <property name="serviceInterface" value="com.tiantian.hessianserver.service.UserService" /> </bean>
注意看我們的HessianServiceExporter對應的bean的name是“/userService”,在SpringMVC的配置文件中,當一個bean的name是以“/”開始的時候Spring會自動對它進行BeanNameUrlHandlerMapping。所以這里相當於是我們把“/userService”映射到了HessianServiceExporter,根據上面的配置我們要請求這個遠程服務的時候應該請求“/api/service/userService”。雖然說在Spring的配置文件中我們把bean的名稱設為以“/”開始時Spring會自動對它進行一個beanName映射,但有一次不知道是哪里影響了,我這樣使用的時候Spring沒有對它進行自動映射,所以為了保險起見,這里我們最好自己指定一個BeanNameUrlHandlerMapping,代碼如下所示:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="userService" class="com.tiantian.hessianserver.service.impl.UserServiceImpl" /> <bean name="/userService" class="org.springframework.remoting.caucho.HessianServiceExporter"> <property name="service" ref="userService" /> <property name="serviceInterface" value="com.tiantian.hessianserver.service.UserService" /> </bean>
注意,因為是根據beanName來進行映射的,所以我們必須要給HessianServiceExporter bean對象指定name屬性,而且其對應的name必須以“/”開頭,這樣我們的客戶端才能訪問到對應的服務。
1.2.3 客戶端整合
對於客戶端要使用遠程的Hessian服務的,我們需要在Spring的配置文件中定義對應的org.springframework.remoting.caucho.HessianProxyFactoryBean bean對象。 HessianProxyFactoryBean對象需要指定兩個屬性,一個是serviceInterface屬性,表示當前請求的遠程服務對應的接口;另一個是serviceUrl屬性,表示當前的遠程服務對應的服務端請求地址。這里在客戶端為了使用hessianServer定義的UserService服務,我們建立一個對應的hessianClient項目,在hessianClient中我們定義一個對應的UserService接口,這個接口的內容跟hessianServer中的UserService接口的內容是一樣的。代碼如下所示:
package com.tiantian.hessianserver.service; public interface UserService { public void addUser(); public void updateUser(); public void delUser(); public String findUser(String username); }
之后我們就在當前Spring的配置文件中定義對應的HessianProxyFactoryBean對象。HessianProxyFactoryBean會根據指定的serviceInterface和serviceUrl屬性返回一個serviceInterface對應的代理對象。這里我們的Spring配置文件這樣定義:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="userService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:8080/hessianServer/api/service/userService" /> <property name="serviceInterface" value="com.tiantian.hessianserver.service.UserService" /> </bean> </beans>
可以看到我們通過HessianProxyFactoryBean定義了一個UserService對應的遠程代理對象,之后我們就可以在我們的程序中把它作為一個普通的bean對象來使用這個UserService的代理對象了。這里我們定義以下測試代碼:
package com.tiantian.hessianclient.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.tiantian.hessianserver.service.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("/applicationContext.xml") public class HessianTest { @Autowired private UserService userService; @Test public void test() { userService.addUser(); userService.updateUser(); userService.delUser(); String user = userService.findUser("ZhangSan"); System.out.println(user); System.out.println("---------------------------------finished----------------------------------"); } }
之后我們啟動我們的hessianServer,然后執行上面的測試程序,在服務端會輸出如下內容:
在客戶端會輸出如下內容:
這說明我們已經成功地調用了遠程服務UserService。
注:
1.Hessian不支持方法的重載,打個比方現在有一AddService,里面有一add(int a, int b)和一add(long a, long b)方法,然后我們把它發布為一個Hessian服務。那么當我們想要遠程訪問AddService的add方法時Hessian會報錯,拋出異常
com.caucho.hessian.io.HessianProtocolException: '?' is an unknown code
因為默認情況下它是不支持方法的重載,這個時候我們可以在客戶端使用的時候新增屬性overloadEnabled,值為true。如:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="userService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:8080/hessianServer/api/service/userService" /> <property name="serviceInterface" value="com.tiantian.hessianserver.service.UserService" /> <!--新增overloadEnabled屬性,並把它的值設置為true,默認是false,則Hessian就能支持方法的重載了。--> <property name="overloadEnabled" value="true" /> </bean> </beans>