一、spring远程调用概览
远程调用指的是客户端应用和服务端之间的会话(RPC)
spring支持多种远程调用技术
1.远程方法调用 RMI
2.Hessian或Burlap
3.HTTP invoker
4.JAX-RPC和JAXWS
二、使用RMI
RMI是在jdk1.1的时候就被引入进来,它为java开发者提供了一种强大的方法来实现java程序间的交互
开发和访问RMI服务很乏味和无聊,因为它涉及到好几个步骤。spring简化了RMI模型,它提供了一个代理工厂bean,能够让我们把RMI服务像本地javaBean那装配到我们的spring应用中。spring还提供了一个远程导出器,能用来简化把Spring管理的bean转换为RMI服务的工作。
1.导出RMI服务(定义RMI服务端)
传统的创建RMI服务的步骤如下:
1.编写一个服务实现类,类中的方法需要抛出RemoteException异常
2.创建一个继承于Remote的服务接口
3.运行RMI编译器,创建客户端stub类和服务端skeleton类
4.启动一个RMI注册表,以便持有这些服务
5.在RMI注册表中注册服务
而spring简化了上面的步骤:
先定义接口
package com.demo.service;
public interface HelloRMIService {
public int getAdd(int a, int b);
}
实现上述接口
package com.demo.service.impl;
import com.demo.service.HelloRMIService;
public class HelloRMIServiceImpl implements HelloRMIService {
public int getAdd(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
在spring配置文件中将上述的pojo配置为rmi服务类
<bean id="myRMIServer" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="helloRMI"></property>
<property name="service" ref="helloRMIServiceImpl"></property>
<property name="serviceInterface" value="com.demo.service.HelloRMIService"></property>
<property name="registryPort" value="9999"></property>
</bean>
这时候就是配置为rmi服务类了
2.装配RMI服务(编写RMI客户端)
传统的RMI需要使用RMI API的Naming类从RMI注册表中查找服务,但是Spring提供了一个便捷的方式,为了方便,下面利用java-project工程作为RMI客户端作为演示。
先编写服务端相同的接口(实际应用中,一般会打成jar包)
package com.demo.service;
public interface HelloRMIService {
public int getAdd(int a, int b);
}
在spring配置文件配置客户端
<!-- 客户端 -->
<bean id="myRMIClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceInterface" value="com.demo.service.HelloRMIService"></property>
<property name="serviceUrl" value="rmi://127.0.0.1:9999/helloRMI"></property>
</bean>
再编写客户端类
package com.demo.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RMIClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/demo/service/rmiClient.xml");
HelloRMIService helloRMIService = applicationContext.getBean("myRMIClient",HelloRMIService.class);
System.out.println(helloRMIService.getAdd(63, 4));
}
}
运行后就可以使用远程服务了
局限:RMI是一种实现远程服务交互的好办法,但是它也是存在某些限制:
1.RMI很难穿越防火墙,这是因为RMI使用任意的端口来交互,这是防火墙不允许的
2.RMI是基于java的,这意味客户端和服务端都必须要用java来进行开发
针对上述的问题,Caucho提供了两种解决方案:Hession和Burlap,下面就来看看这两种方法是如何处理的
三、使用Hession和Burlap发布远程服务
Hessian和Burlap的优势是不同的,Hession的消息是二进制的,可以移植到其他的非java语言中。Burlap的消息是XML格式的,两者的应用场景是不同的
1.使用Hessian和Burlap导出bean的功能(配置服务端)
先看spring中使用Hession:
配置Hession服务端:
先在pom.xml文件中引入相关的jar包:
<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-remoting -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<version>2.0.8</version>
</dependency>
定义相关的接口
package com.demo.service;
public interface HelloHessianService {
public int getAdd(int a, int b);
}
下面是实现的接口:
package com.demo.service.impl;
import com.demo.service.HelloHessianService;
public class HelloHessianServiceImpl implements HelloHessianService {
public int getAdd(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
接着在web.xml中配置DispatcherServlet.xml
<servlet>
<servlet-name>hessian</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hessian</servlet-name>
<url-pattern>/hessian.service</url-pattern>
</servlet-mapping>
新建hessian.servlet.xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd ">
<bean id="myService" class="com.demo.service.impl.HelloHessianServiceImpl"/>
<!-- hessian是基于Http的二进制码传输的轻量级框架 -->
<bean id="hessianExporter" class="org.springframework.remoting.caucho.HessianServiceExporter">
<!-- 服务 -->
<property name="service" ref="myService"/>
<!--hessian没有类似rmi服务注册表,不需要用服务名注册, -->
<!-- 绑定服务的路径 -->
<property name="serviceInterface" value="com.demo.service.HelloHessianService"/>
</bean>
<!-- 2.5.6版本相应的jar包在dist/modules/spring-webmvc -->
<bean id="hessianMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hessian.service">hessianExporter</prop>
</props>
</property>
</bean>
<!-- 因为hessianExporter在SpringMVC里面作为一个controller实现的,所以还需要在web.xml中配置 -->
</beans>
至此,hession服务端就配置好了
下面开始配置Burlap服务端:
先定义接口:
package com.demo.service;
public interface HelloBurlapService {
public int getAdd(int a, int b);
}
实现上面的接口:
package com.demo.service.impl;
import com.demo.service.HelloBurlapService;
public class HelloBurlapServiceImpl implements HelloBurlapService {
public int getAdd(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
接着在web.xml中配置DispatcherServlet.xml
<servlet>
<servlet-name>burlap</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>burlap</servlet-name>
<url-pattern>/burlap.service</url-pattern>
</servlet-mapping>
新建burlap-servlet.xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd ">
<!-- 服务 ,需要引入/lib/caucho/hessian.jar -->
<bean id="myBurlapService" class="com.demo.service.impl.HelloBurlapServiceImpl" />
<!-- burlap是基于xml传输的轻量级框架 -->
<bean name="burlapExporter"
class="org.springframework.remoting.caucho.BurlapServiceExporter">
<!-- 服务 -->
<property name="service" ref="myBurlapService" />
<!-- 绑定服务的路径 -->
<property name="serviceInterface" value="com.demo.service.HelloBurlapService" />
</bean>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/burlap.service">burlapExporter</prop>
</props>
</property>
</bean>
</beans>
至此,burlap服务端就配置好
2.访问Hessian/Burlap服务(编写客户端)
先编写Hessian客户端
定义接口:
package com.demo.service;
public interface HelloHessianService {
public int getAdd(int a, int b);
}
编写spring配置文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 客户端 -->
<bean id="myHessionClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<!-- 服务URL -->
<property name="serviceUrl" value="http://localhost:8080/hessian.service"/>
<!-- 本地接口路径 -->
<property name="serviceInterface" value="com.demo.service.HelloHessianService"/>
</bean>
</beans>
注意:客户端也需要引入下面的jar包:
<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-remoting -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<version>2.0.8</version>
</dependency>
接着编写客户端:
package com.demo.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HessionClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/demo/service/hessionClient.xml");
HelloHessianService helloHessianService = applicationContext.getBean("myHessionClient",HelloHessianService.class);
System.out.println(helloHessianService.getAdd(63, 6666));
}
}
Burlap的客户端的编写也是类似的:
先定义接口
package com.demo.service;
public interface HelloBurlapService {
public int getAdd(int a, int b);
}
然后在spring配置文件配置
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 客户端 -->
<bean id="myBurlapClient" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
<!-- 服务URL -->
<property name="serviceUrl" value="http://localhost:8080/burlap.service"/>
<!-- 本地接口路径 -->
<property name="serviceInterface" value="com.demo.service.HelloBurlapService"/>
</bean>
</beans>
接着编写burlap客户端:
package com.demo.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BurlapClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/demo/service/burlapClient.xml");
HelloBurlapService helloBurlapService = applicationContext.getBean("myBurlapClient",HelloBurlapService.class);
System.out.println(helloBurlapService.getAdd(63, 236));
}
}
至此,两种客户端都编写完毕,这时候是可以调用远程的服务了
上面的例子遗憾的是还没有体现出hession和burlap的区别。
Hession和Burlap是基于HTTP开发的,它能解决RMI防火墙的问题,但是如果数据模型非常复杂的话,那么Hession和Burlap是无法胜任的,这时候又有另外一种解决方法,那就是使用Spring的HTTP invoker
四、使用Spring的HttpInvoker
HttpInvoder的配置和Hession还有Burlap是非常的相似的
1.将bean导出为HttpInvoker服务(配置HttpInvoker服务)
定义接口:
package com.demo.service;
public interface HelloInvokerService {
public int getAdd(int a, int b);
}
实现接口
package com.demo.service.impl;
import com.demo.service.HelloInvokerService;
public class HelloInvokerServiceImpl implements HelloInvokerService {
public int getAdd(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
在web.xml配置Servlet
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/invoker.service</url-pattern>
</servlet-mapping>
编写invoker-servlet.xml文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd ">
<bean id="myInvokerService" class="com.demo.service.impl.HelloInvokerServiceImpl"/>
<bean id="invokerExporter" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<!-- 服务 -->
<property name="service" ref="myInvokerService"/>
<!-- 绑定服务的路径 -->
<property name="serviceInterface" value="com.demo.service.HelloInvokerService"/>
</bean>
<!-- 2.5.6版本相应的jar包在dist/modules/spring-webmvc -->
<bean id="invokerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/invoker.service">invokerExporter</prop>
</props>
</property>
</bean>
</beans>
至此,HttpInvoker就配置完毕了
2.通过Http访问服务(编写invoker客户端)
定义相同的接口:
package com.demo.service;
public interface HelloInvokerService {
public int getAdd(int a, int b);
}
编写Spring配置文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 客户端 -->
<bean id="myInvokerClient" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<!-- 服务URL -->
<property name="serviceUrl" value="http://localhost:8080/invoker.service"/>
<!-- 本地接口路径 -->
<property name="serviceInterface" value="com.demo.service.HelloInvokerService"/>
</bean>
</beans>
编写客户端
package com.demo.service;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InvokerClient {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/demo/service/invokerClient.xml");
HelloInvokerService helloInvokerService = applicationContext.getBean("myInvokerClient",HelloInvokerService.class);
System.out.println(helloInvokerService.getAdd(63, 236111));
}
}
至此,HttpInvoker客户端编写完毕
五、发布和使用Web服务
这是关于webservice的知识点,详细看如下的文章(暂时未完成!)