Spring 整合 Hessian 訪問遠(yuǎn)程服務(wù)
目錄
1.1 ???? Hessian 簡(jiǎn)介
?????? Hessian 是一個(gè)輕量級(jí)的 Web 服務(wù)實(shí)現(xiàn)工具,它采用的是二進(jìn)制協(xié)議,因此很適合發(fā)送二進(jìn)制數(shù)據(jù)。它的一個(gè)基本原理就是把遠(yuǎn)程服務(wù)對(duì)象以二進(jìn)制的方式進(jìn)行發(fā)送和接收。
1.2 ???? 整合
1.2.1?概述
對(duì)于 Hessian 而言,有服務(wù)端和客戶端,所以我們的整合也需要分服務(wù)端的整合和客戶端的整合。服務(wù)端的整合是通過 SpringMVC 進(jìn)行的,而客戶端的整合則是通過 Spring 的 bean 進(jìn)行的。
1.2.2?服務(wù)端整合
基于客戶端要調(diào)用服務(wù)端的遠(yuǎn)程服務(wù),所以我們先來談一下服務(wù)端的整合。 Hessian 的遠(yuǎn)程服務(wù)是基于接口的,所以我們要作為遠(yuǎn)程服務(wù)的實(shí)現(xiàn)類必須要實(shí)現(xiàn)一個(gè)接口。作為示例,這里我們建立一個(gè)叫 hessianServer 的 web 項(xiàng)目作為遠(yuǎn)程服務(wù)的服務(wù)端,在這個(gè)項(xiàng)目中我們建立一個(gè)叫做 UserService 的接口:
package com.tiantian.hessianserver.service; public interface UserService { public void addUser(); public void updateUser(); public void delUser(); public String findUser(String username); }
?
?????? 然后建立一個(gè)它的實(shí)現(xiàn)類 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 作為一個(gè)遠(yuǎn)程服務(wù)進(jìn)行發(fā)布,以致客戶端能夠進(jìn)行訪問。
?????? 首先我們需要在 web.xml 中配置一個(gè) SpringMVC 的 DispatcherServlet 用于接收所有的 Web 服務(wù)請(qǐng)求,這里我們這樣配置:
<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>
?
?????? 可以看到我們這個(gè) DispatcherServlet 會(huì)處理 url 為“ /api/service/* ”的請(qǐng)求,通配符“ * ”就對(duì)應(yīng)著我們的處理器映射。
?????? 接下來就是在 SpringMVC 的配置文件中利用 Hessian 來定義我們的遠(yuǎn)程服務(wù)了,這是通過 Spring 提供的 HessianServiceExporter 來實(shí)現(xiàn)的。我們需要在 SpringMVC 的配置文件中定義一個(gè)類型為 HessianServiceExporter 的 bean 對(duì)象。該 bean 對(duì)象需要接收兩個(gè)屬性,一個(gè)是 service 屬性,用于關(guān)聯(lián)真正的 service 對(duì)象,另一個(gè)是 serviceInterface 屬性,用于指定當(dāng)前的服務(wù)對(duì)應(yīng)的接口。 HessianServiceExporter 實(shí)現(xiàn)了 HttpRequestHandler 接口,當(dāng)我們請(qǐng)求某一個(gè)遠(yuǎn)程服務(wù)的時(shí)候?qū)嶋H上請(qǐng)求的就是其對(duì)應(yīng)的 HessianServiceExporter 對(duì)象, HessianServiceExporter 會(huì)把請(qǐng)求的服務(wù)以二進(jìn)制的方式返回給客戶端。這里我們?cè)? 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 對(duì)應(yīng)的 bean 的 name 是“ /userService ”,在 SpringMVC 的配置文件中,當(dāng)一個(gè) bean 的 name 是以“ / ”開始的時(shí)候 Spring 會(huì)自動(dòng)對(duì)它進(jìn)行 BeanNameUrlHandlerMapping 。所以這里相當(dāng)于是我們把“ /userService ”映射到了 HessianServiceExporter ,根據(jù)上面的配置我們要請(qǐng)求這個(gè)遠(yuǎn)程服務(wù)的時(shí)候應(yīng)該請(qǐng)求“ /api/service/userService ”。雖然說在 Spring 的配置文件中我們把 bean 的名稱設(shè)為以“ / ”開始時(shí) Spring 會(huì)自動(dòng)對(duì)它進(jìn)行一個(gè) beanName 映射,但有一次不知道是哪里影響了,我這樣使用的時(shí)候 Spring 沒有對(duì)它進(jìn)行自動(dòng)映射,所以為了保險(xiǎn)起見,這里我們最好自己指定一個(gè) 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>
?
?????? 注意,因?yàn)槭歉鶕?jù) beanName 來進(jìn)行映射的,所以我們必須要給 HessianServiceExporter bean 對(duì)象指定 name 屬性,而且其對(duì)應(yīng)的 name 必須以“ / ”開頭,這樣我們的客戶端才能訪問到對(duì)應(yīng)的服務(wù)。
1.2.3?客戶端整合
對(duì)于客戶端要使用遠(yuǎn)程的 Hessian 服務(wù)的,我們需要在 Spring 的配置文件中定義對(duì)應(yīng)的 org.springframework.remoting.caucho.HessianProxyFactoryBean bean 對(duì)象。 ???? HessianProxyFactoryBean 對(duì)象需要指定兩個(gè)屬性,一個(gè)是 serviceInterface 屬性,表示當(dāng)前請(qǐng)求的遠(yuǎn)程服務(wù)對(duì)應(yīng)的接口;另一個(gè)是 serviceUrl 屬性,表示當(dāng)前的遠(yuǎn)程服務(wù)對(duì)應(yīng)的服務(wù)端請(qǐng)求地址。這里在客戶端為了使用 hessianServer 定義的 UserService 服務(wù),我們建立一個(gè)對(duì)應(yīng)的 hessianClient 項(xiàng)目,在 hessianClient 中我們定義一個(gè)對(duì)應(yīng)的 UserService 接口,這個(gè)接口的內(nèi)容跟 hessianServer 中的 UserService 接口的內(nèi)容是一樣的。代碼如下所示:
package com.tiantian.hessianserver.service; public interface UserService { public void addUser(); public void updateUser(); public void delUser(); public String findUser(String username); }
?
?????? 之后我們就在當(dāng)前 Spring 的配置文件中定義對(duì)應(yīng)的 HessianProxyFactoryBean 對(duì)象。 HessianProxyFactoryBean 會(huì)根據(jù)指定的 serviceInterface 和 serviceUrl 屬性返回一個(gè) serviceInterface 對(duì)應(yīng)的代理對(duì)象。這里我們的 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 定義了一個(gè) UserService 對(duì)應(yīng)的遠(yuǎn)程代理對(duì)象,之后我們就可以在我們的程序中把它作為一個(gè)普通的 bean 對(duì)象來使用這個(gè) UserService 的代理對(duì)象了。這里我們定義以下測(cè)試代碼:
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----------------------------------"); } }
?
?????? 之后我們啟動(dòng)我們的 hessianServer ,然后執(zhí)行上面的測(cè)試程序,在服務(wù)端會(huì)輸出如下內(nèi)容:
?????? 在客戶端會(huì)輸出如下內(nèi)容:
?????? 這說明我們已經(jīng)成功地調(diào)用了遠(yuǎn)程服務(wù) UserService 。
注:
? ? 1.Hessian不支持方法的重載,打個(gè)比方現(xiàn)在有一AddService,里面有一add(int a, int b)和一add(long a, long b)方法,然后我們把它發(fā)布為一個(gè)Hessian服務(wù)。那么當(dāng)我們想要遠(yuǎn)程訪問AddService的add方法時(shí)Hessian會(huì)報(bào)錯(cuò),拋出異常
com.caucho.hessian.io.HessianProtocolException: '?' is an unknown code
因?yàn)槟J(rèn)情況下它是不支持方法的重載,這個(gè)時(shí)候我們可以在客戶端使用的時(shí)候新增屬性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屬性,并把它的值設(shè)置為true,默認(rèn)是false,則Hessian就能支持方法的重載了。--> <property name="overloadEnabled" value="true" /> </bean> </beans>
?
? ? ? ?2.完整
源碼請(qǐng)查看附件。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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