Spring 整合 Hessian 訪問遠程服務(wù)
目錄
1.1 ???? Hessian 簡介
?????? Hessian 是一個輕量級的 Web 服務(wù)實現(xiàn)工具,它采用的是二進制協(xié)議,因此很適合發(fā)送二進制數(shù)據(jù)。它的一個基本原理就是把遠程服務(wù)對象以二進制的方式進行發(fā)送和接收。
1.2 ???? 整合
1.2.1?概述
對于 Hessian 而言,有服務(wù)端和客戶端,所以我們的整合也需要分服務(wù)端的整合和客戶端的整合。服務(wù)端的整合是通過 SpringMVC 進行的,而客戶端的整合則是通過 Spring 的 bean 進行的。
1.2.2?服務(wù)端整合
基于客戶端要調(diào)用服務(wù)端的遠程服務(wù),所以我們先來談一下服務(wù)端的整合。 Hessian 的遠程服務(wù)是基于接口的,所以我們要作為遠程服務(wù)的實現(xiàn)類必須要實現(xiàn)一個接口。作為示例,這里我們建立一個叫 hessianServer 的 web 項目作為遠程服務(wù)的服務(wù)端,在這個項目中我們建立一個叫做 UserService 的接口:
package com.tiantian.hessianserver.service;
public interface UserService {
public void addUser();
public void updateUser();
public void delUser();
public String findUser(String username);
}
?
?????? 然后建立一個它的實現(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 作為一個遠程服務(wù)進行發(fā)布,以致客戶端能夠進行訪問。
?????? 首先我們需要在 web.xml 中配置一個 SpringMVC 的 DispatcherServlet 用于接收所有的 Web 服務(wù)請求,這里我們這樣配置:
<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/* ”的請求,通配符“ * ”就對應(yīng)著我們的處理器映射。
?????? 接下來就是在 SpringMVC 的配置文件中利用 Hessian 來定義我們的遠程服務(wù)了,這是通過 Spring 提供的 HessianServiceExporter 來實現(xiàn)的。我們需要在 SpringMVC 的配置文件中定義一個類型為 HessianServiceExporter 的 bean 對象。該 bean 對象需要接收兩個屬性,一個是 service 屬性,用于關(guān)聯(lián)真正的 service 對象,另一個是 serviceInterface 屬性,用于指定當(dāng)前的服務(wù)對應(yīng)的接口。 HessianServiceExporter 實現(xiàn)了 HttpRequestHandler 接口,當(dāng)我們請求某一個遠程服務(wù)的時候?qū)嶋H上請求的就是其對應(yīng)的 HessianServiceExporter 對象, HessianServiceExporter 會把請求的服務(wù)以二進制的方式返回給客戶端。這里我們在 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 對應(yīng)的 bean 的 name 是“ /userService ”,在 SpringMVC 的配置文件中,當(dāng)一個 bean 的 name 是以“ / ”開始的時候 Spring 會自動對它進行 BeanNameUrlHandlerMapping 。所以這里相當(dāng)于是我們把“ /userService ”映射到了 HessianServiceExporter ,根據(jù)上面的配置我們要請求這個遠程服務(wù)的時候應(yīng)該請求“ /api/service/userService ”。雖然說在 Spring 的配置文件中我們把 bean 的名稱設(shè)為以“ / ”開始時 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>
?
?????? 注意,因為是根據(jù) beanName 來進行映射的,所以我們必須要給 HessianServiceExporter bean 對象指定 name 屬性,而且其對應(yīng)的 name 必須以“ / ”開頭,這樣我們的客戶端才能訪問到對應(yīng)的服務(wù)。
1.2.3?客戶端整合
對于客戶端要使用遠程的 Hessian 服務(wù)的,我們需要在 Spring 的配置文件中定義對應(yīng)的 org.springframework.remoting.caucho.HessianProxyFactoryBean bean 對象。 ???? HessianProxyFactoryBean 對象需要指定兩個屬性,一個是 serviceInterface 屬性,表示當(dāng)前請求的遠程服務(wù)對應(yīng)的接口;另一個是 serviceUrl 屬性,表示當(dāng)前的遠程服務(wù)對應(yīng)的服務(wù)端請求地址。這里在客戶端為了使用 hessianServer 定義的 UserService 服務(wù),我們建立一個對應(yīng)的 hessianClient 項目,在 hessianClient 中我們定義一個對應(yīng)的 UserService 接口,這個接口的內(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 的配置文件中定義對應(yīng)的 HessianProxyFactoryBean 對象。 HessianProxyFactoryBean 會根據(jù)指定的 serviceInterface 和 serviceUrl 屬性返回一個 serviceInterface 對應(yīng)的代理對象。這里我們的 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 對應(yīng)的遠程代理對象,之后我們就可以在我們的程序中把它作為一個普通的 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 ,然后執(zhí)行上面的測試程序,在服務(wù)端會輸出如下內(nèi)容:
?????? 在客戶端會輸出如下內(nèi)容:
?????? 這說明我們已經(jīng)成功地調(diào)用了遠程服務(wù) UserService 。
注:
? ? 1.Hessian不支持方法的重載,打個比方現(xiàn)在有一AddService,里面有一add(int a, int b)和一add(long a, long b)方法,然后我們把它發(fā)布為一個Hessian服務(wù)。那么當(dāng)我們想要遠程訪問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屬性,并把它的值設(shè)置為true,默認是false,則Hessian就能支持方法的重載了。-->
<property name="overloadEnabled" value="true" />
</bean>
</beans>
?
? ? ? ?2.完整
源碼請查看附件。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

