如果我們需要擷取目前的天氣狀況,我們可以通過氣象局提供的一個接口并調用方法來擷取,這是因為氣象局釋出了一個遠端服務,我們可以通過接口來調用他的遠端方法,擷取到天氣資訊,一般釋出并使用遠端服務的有RMI ,hessian和brulap ,以及spring的invoker,他們各有優缺點, 這裡隻介紹RMI和spring的invoker
一、使用RMI釋出一個遠端服務
首先我們需要定義一個接口,這個接口對外公開
package main.java.test.rmi;
import java.util.List;
public interface FruitService {
List<Fruit> getFruitList();
}
然後還需要一個接口的實作類:
package main.java.test.rmi;
import java.util.ArrayList;
import java.util.List;
public class FruitServiceImpl implements FruitService {
public List<Fruit> getFruitList() {
List<Fruit> list = new ArrayList<Fruit>();
Fruit f1 = new Fruit();
f1.setName("橙子");
f1.setColor("黃色");
Fruit f2 = new Fruit();
f2.setName("蘋果");
f2.setColor("紅色");
list.add(f1);
list.add(f2);
return list;
}
}
這裡用到的實體類是Fruit,實體類必須序列化
package main.java.test.rmi;
import java.io.Serializable;
public class Fruit implements Serializable {
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
然後就是配置了, 在spring的配置檔案中配置
<!-- spring內建RMI遠端服務 -->
<bean id="messageService" class="main.java.test.rmi.MessageProviderImp"></bean>
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- RMI服務名稱,可自定義服務名稱 -->
<property name="serviceName" value="MessageService" />
<!-- 導出實體 -->
<property name="service" ref="messageService" />
<!-- 導出接口 -->
<property name="serviceInterface" value="main.java.test.rmi.MessageProvider" />
<!-- spring預設使用1099端口 -->
<property name="registryPort" value="1199" />
</bean>
這樣啟動項目,這個服務就釋出出去了
二、通路RMI遠端服務
也就是用戶端通路遠端服務的時候,需要在用戶端的spring配置檔案中配置:
<bean id="messageService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://192.168.1.100:1199/MessageService" />
<property name="serviceInterface" value="org.thera.rmi.service.MessageProvider" />
</bean>
這樣在項目中擷取這個bean強轉成接口調用相應的方法就可以了
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/context.xml");
System.out.println("加載Spring容器,并初始化RMI用戶端");
MessageProvider client = (MessageProvider)ctx.getBean("messageService");
String temp = client.queryForMessage("LvSantorini");
System.out.println("傳回結果: " + temp);
}
}
這就是RMI釋出以及調用遠端服務的執行個體
三、釋出spring的invoker遠端服務
invoker是spring為了解決RMI和hessian的缺陷而出現的一個服務,釋出一個invoker遠端服務的步驟如下,他的接口,實作類以及實體類都是采用上面定義了的接口和接口實作類
首先,使用invoker就需要使用spring,我們使用的springmvc架構,在這裡需要定義一個接口調用的url,比如我們就定義為/user.service, 這樣用戶端就可以通過這個url來擷取服務,手下那我們需要在web中攔截到這個請求,/*包含/user.service
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:main/resource/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:main/resource/applicationContext.xml</param-value>
</context-param>
因為這個url請求不同于其他的請求,是以需要為這個請求單獨處理一個bean,在mvc的配置檔案中這樣配置:
<?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:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd ">
<!-- <mvc:resources location="/html/" mapping="/html/**"/>
<mvc:resources location="/js/" mapping="/js/**"/> -->
<mvc:resources location="/" mapping="/**/*.html"/>
<mvc:resources location="/" mapping="/**/*.js"/>
<mvc:resources location="/" mapping="/**/*.jsp"/>
<context:component-scan
base-package="main.java">
</context:component-scan>
<mvc:annotation-driven/>
<bean id="userServices" class="main.java.test.rmi.FruitServiceImpl" />
<bean id="userServiceInvoker"
class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="userServices" />
<property name="serviceInterface" value="main.java.test.rmi.FruitService">
</property>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/user.service">userServiceInvoker</prop>
</props>
</property>
</bean>
</beans>
這樣就遠端服務就釋出出去了
四、擷取invoker遠端服務
擷取invoker遠端服務就需要在spring配置檔案中這樣配置:
<bean id="httpService1"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://localhost:80/user.service</value>
</property>
<property name="serviceInterface" value="main.java.test.rmi.FruitService">
</property>
</bean>
配置服務擷取bean,這樣在任意地方通過
FruitService client = (FruitService)BeanUtil.getBeanByName("httpService1");
System.out.println("invoker "+client.getFruitList().size());
就可以擷取到服務方法了是不是很簡單
五、優缺點以及問題
rmi是一種很好的實作與遠端服務互動的非常好的方式,但是他存在某些限制, 首先,他很難穿越防火牆,其次就是rmi是基于java的也就是用戶端和服務端都必須采用java 開發,
invoker是一個座位兩全其美的遠端調用解決方案二出現的,但是他有一個嚴重的限制,就是他的用戶端呢服務端都必須是spring應用,也隐含的表名了用戶端和服務端必須是基于java的
問題:①invoker配置urlmapping時,必須是在springmvc的配置servlet配置檔案中,而不是在spring的配置檔案。