Spring 整合 Hessian 訪問遠程服務
目錄
1.1 ???? Hessian 簡介
?????? Hessian 是一個輕量級的 Web 服務實現工具,它采用的是二進制協議,因此很適合發送二進制數據。它的一個基本原理就是把遠程服務對象以二進制的方式進行發送和接收。
1.2 ???? 整合
1.2.1?概述
對于 Hessian 而言,有服務端和客戶端,所以我們的整合也需要分服務端的整合和客戶端的整合。服務端的整合是通過 SpringMVC 進行的,而客戶端的整合則是通過 Spring 的 bean 進行的。
1.2.2?服務端整合
基于客戶端要調用服務端的遠程服務,所以我們先來談一下服務端的整合。 Hessian 的遠程服務是基于接口的,所以我們要作為遠程服務的實現類必須要實現一個接口。作為示例,這里我們建立一個叫 hessianServer 的 web 項目作為遠程服務的服務端,在這個項目中我們建立一個叫做 UserService 的接口:
package com.tiantian.hessianserver.service; public interface UserService { public void addUser(); public void updateUser(); public void delUser(); public String findUser(String username); }
?
?????? 然后建立一個它的實現類 UserServiceImpl :
package com.tiantian.hessianserver.service.impl; import com.tiantian.hessianserver.service.UserService; public class UserServiceImpl implements UserService { public void addUser() { System.out.println("-------------invoke addUser()---------------"); } public void updateUser() { System.out.println("-------------invoke updateUser()---------------"); } public void delUser() { System.out.println("-------------invoke delUser()---------------"); } public String findUser(String username) { System.out.println("-------------invoke findUser---------------"); return "return: " + username; } }
?
?????? 那么接下來我們要做的就是把 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>
?
? ? ? ?2.完整
源碼請查看附件。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
