如果我们需要获取当前的天气状况,我们可以通过气象局提供的一个接口并调用方法来获取,这是因为气象局发布了一个远程服务,我们可以通过接口来调用他的远程方法,获取到天气信息,一般发布并使用远程服务的有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的配置文件。