rmi of spring
http://yingxiong.iteye.com/blog/174453
基于Spring實現遠程服務編程:
[urlhttp://www.51cto.com/art/200611/34262.htm][/url]
用Spring動態調用RMI遠程對象 ???
// 不需要通過BeanFactory直接動態調用遠程對象
DistributeCenterBO distributeCenterBO = null;
RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
rmiProxyFactoryBean.setServiceInterface(DistributeCenterBO.class);
rmiProxyFactoryBean.setServiceUrl(
"rmi://localhost:1199/DistributeCenterBO");
try {
rmiProxyFactoryBean.afterPropertiesSet(); //更改ServiceInterface或ServiceUrl之后必須調用該方法,來獲取遠程調用樁
} catch (Exception ex) {
}
if (rmiProxyFactoryBean.getObject() instanceof DistributeCenterBO) {
distributeCenterBO = (DistributeCenterBO)
rmiProxyFactoryBean.getObject();
distributeCenterBO.register(SubscriberImpl.subscriberId);
}
rmi和httpInvoker
對于富客戶端來說,和服務器端的通訊有很多種方式,不過我一般用的就是rmi或者httpInvoker。
spring為多種遠程調用都提供了包裝:
一。對于RMI來說
1、服務器端: <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
? <property name="serviceName"><value>ExampleService</value></property>
? <property name="service"><ref bean="exampleManager"/></property>
? <property name="serviceInterface"><value>com.example.server.service.manager.base.IExampleManager</value></property>
? <property name="registryPort"><value>777</value></property>
</bean>
Spring中合理的配置RMI:
因為RMI stub被連接到特定的端點,不僅僅是為每個調用打開一個給定的目標地址的連接,所以如果重新啟動RMI端點主機的服務器,那么就需要重新注冊這些stub,并且客戶端需要再次查詢它們。
???? 雖然目標服務的重新注冊在重新啟動時通常會自動發生,不過此時客戶端保持的stub將會變的陳舊,且客戶端不會注意這些,除非他們再次嘗試調用stub上的方法,而這也將throw一個連接失敗的異常。
????? 為了避免這種情形,Spring的RmiProxyFactoryBean提供了一個refreshStubOnConnectFailure的bean屬性,如果調用失敗,并且連接異常的話,將它設定為true來強制重新自動查詢stub。
<bean id="reportService"
? class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
? <property name="serviceUrl">
?? <value>${showcasewiz.report.serviceurl}</value>
? </property>
? <property name="serviceInterface">
?? <value>com.meetexpo.showcase.backend.service.ReportService</value>
? </property>
? <property name="refreshStubOnConnectFailure">
??? <value>true</value>
? </property>
</bean>
????? stub查詢的另一個問題是,目標RMI服務器和RMI注冊項在查詢時要為可用的。如果客戶端在服務器啟動之前,嘗試查詢和緩存該服務stub,那么客戶端的啟動將會失敗(即使還不需要該服務)。
???? 為了能夠惰性查詢服務stub,設定RmiProxyFactoryBean的lookupStubOnStarup標志為false。然后在第一次訪問時查詢該stub,也就是說,當代理上的第一個方法被調用的時候去主動查詢stub,同時被緩存。這也有一個缺點,就是直到第一次調用,否則無法確認目標服務是否實際存在。
<bean id="reportService"
? class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
? <property name="serviceUrl">
?? <value>${showcasewiz.report.serviceurl}</value>
? </property>
? <property name="serviceInterface">
?? <value>com.meetexpo.showcase.backend.service.ReportService</value>
? </property>
? <property name="lookupStubOnStartup">
???? <value>false</value>
? </property>
? <property name="refreshStubOnConnectFailure">
??? <value>true</value>
? </property>
</bean>
還有一個屬性就是cacheStub,當它設置為false的時候,就完全避免了stub的緩存,但影響了性能。需要的時候還是可以試試。
這段spring的配置文件就定義了服務器端的一個bean,可以暴露給客戶端通過RMI方式來訪問了。
examleMaanger這個bean在實現時,完全不需要知道它自己有一天還會被通過rmi方式被遠程訪問。
2、客戶端:
<bean id="cityService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
??????? <property name="serviceUrl"><value>rmi://localhost:777/CityService</value></property>
??????? <property name="serviceInterface"><value>com.example.server.service.manager.base.IExampleManager</value></property>
??????? <property name="lookupStubOnStartup"><value>true</value></property>
??????? <property name="cacheStub"><value>true</value></property>
??? </bean>這段spring的配置文件定義了客戶端的一個bean,這樣就可在客戶端使用exampleManager了,就如同在本地使用一樣,完全沒有什么不同。
二。對于httpInvoker來說,其配置比rmi方式要麻煩一些,而且據說其效率也要比rmi方式差,不過這一點我到沒有親身證實過,只是聽說而已。但是httpInvoker有一個優點卻足以抵消其所有的缺點,那就是它是通過web的端口來訪問的。這樣,只要能夠瀏覽頁面,就能夠進行遠程調用,避免了rmi方式有時無法通過防火墻的問題。
1、服務器端:
httpInvoker需要web容器的支持,因此需要將服務器端程序部署到web容器內。
在web.xml文件中
??? <listener>
??????? <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
??? </listener>
??? <servlet>
??????? <servlet-name>remote</servlet-name>
??????? <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
??????? <load-on-startup>1</load-on-startup>
??? </servlet>
??? <servlet-mapping>
??????? <servlet-name>remote</servlet-name>
??????? <url-pattern>/remote/*</url-pattern>
??? </servlet-mapping>
注意第一行定義的listener一定要有,否則下面提到的remote-servlet.xml中要引用的bean就會無法找到。
我們定義了一個servlet,名字叫remote,因此在WEB-INF目錄下我們建一個名字為remote-servlet.xml的文件,內容為
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
??? "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
??? <bean name="/exampleService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
??????? <property name="service"><ref bean="exampleManager"/></property>
??????? <property name="serviceInterface">
??????????? <value>com.example.server.service.manager.IExampleManager</value>
??????? </property>
??? </bean>
</beans>這樣服務器端的配置就完成了。exampleManager這個bean被暴露給了客戶端
2、客戶端:
<bean id="exampleService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
??????? <property name="serviceUrl">
??????????? <value>http://localhost:80/remote/exampleService</value>
??????? </property>
??????? <property name="serviceInterface">
??????????? <value>com.example.server.service.manager.IExampleManager</value>
??????? </property>
??? </bean> OK,這樣客戶端的配置就完成了。
?
http://doc.javanb.com/spring-framework-reference-zh-2-0-5/ch17s02.html
?
17.2.?使用RMI暴露服務
使用Spring的RMI支持,你可以通過RMI基礎設施透明的暴露你的服務。設置好Spring的RMI支持后,你會看到一個和遠程EJB接口類似的配置,只是沒有對安全上下文傳遞和遠程事務傳遞的標準支持。當使用RMI調用器時,Spring對這些額外的調用上下文提供了鉤子,你可以在此插入安全框架或者定制的安全證書。
17.2.1.?使用 RmiServiceExporter 暴露服務
使用 RmiServiceExporter,我們可以把AccountService對象的接口暴露成RMI對象。可以使用 RmiProxyFactoryBean 或者在傳統RMI服務中使用普通RMI來訪問該接口。RmiServiceExporter 顯式地支持使用RMI調用器暴露任何非RMI的服務。
當然,我們首先需要在Spring BeanFactory中設置我們的服務:
<bean id="accountService" class="example.AccountServiceImpl"><!-- any additional properties, maybe a DAO? --> </bean>然后,我們將使用 RmiServiceExporter 來暴露我們的服務:
<bean class="org.springframework.remoting.rmi.RmiServiceExporter"><!-- does not necessarily have to be the same name as the bean to be exported --><property name="serviceName" value="AccountService"/><property name="service" ref="accountService"/><property name="serviceInterface" value="example.AccountService"/><!-- defaults to 1099 --><property name="registryPort" value="1199"/> </bean>正如你所見,我們覆蓋了RMI注冊的端口號。通常,你的應用服務也會維護RMI注冊,最好不要和它沖突。更進一步來說,服務名是用來綁定下面的服務的。所以本例中,服務綁定在 rmi://HOST:1199/AccountService。在客戶端我們將使用這個URL來鏈接到服務。
注意:我們省略了一個屬性,就是 servicePort 屬性,它的默認值為0。 這表示在服務通信時使用匿名端口。當然如果你愿意的話,也可以指定一個不同的端口。
17.2.2.?在客戶端鏈接服務
我們的客戶端是一個使用AccountService來管理account的簡單對象:
public class SimpleObject {private AccountService accountService;public void setAccountService(AccountService accountService) {this.accountService = accountService;} }為了把服務連接到客戶端上,我們將創建另一個單獨的bean工廠,它包含這個簡單對象和服務鏈接配置位:
<bean class="example.SimpleObject"><property name="accountService" ref="accountService"/> </bean><bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"><property name="serviceUrl" value="rmi://HOST:1199/AccountService"/><property name="serviceInterface" value="example.AccountService"/> </bean>這就是我們在客戶端為支持遠程account服務所需要做的。Spring將透明的創建一個調用器并且通過RmiServiceExporter使得account服務支持遠程服務。在客戶端,我們用RmiProxyFactoryBean連接它。
?
總結
以上是生活随笔為你收集整理的rmi of spring的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts1.2配置详解
- 下一篇: SLF4J 教程(自由在各种log中切换