简述Spring集成模块中的远程服务的四种方式


文章初衷为个人学习笔记,存在措辞不当和理解不深入,多包涵、指教。本例主要是在SpringBoot中开发,纯Spring需要一定调整。

RPC和REST区别

	RPC(远程服务调用,remote procedure call)是客户端与服务端中间的会话。
	实际项目开发中,不可避免存在需要引用其他项目功能,使用远程服务暴露这些功能是其中一种解决方法。
	REST(表述性状态转移 ,Representational State Transfer)一种错误的认证是,将其归纳为一种基于Web的
	远程服务调用,然REST与RPC没有任何直接关系,RPC是面向服务,RSET正如其名,是一种描述资源状
	态以最适合客户端或服务器的形式,从一端转移至另一端。

Spring 中的多种远程调用技术支持RPC

	Spring支持多种不同的RPC模型,包含RMI、Caucho的Hessian和Burlab、Spring自带的HTTP invoker。
	和独立于平台的JAX-RPC和JAX-WS。

Spring中多种远程调用技术

在这里插入图片描述
这个模型在几种Spring远程服务实现方式通用,主要流程是,服务提供方(以下简称服务端)需要将开发服务作为一个Spring导出bean,客户端通过一个Spring代理向服务端发起调用。在此过程中,由于采用了Spring作为远程服务的管理者,Spring会捕获一些异常(如java.rmi.RemoteException等),将其重新抛出为非检查性异常,可以让使用者选择是否显示捕获这些异常。

RMI方式

RMI最初在JDK1.1引入到Java平台中,为Java开发者提供了一种实现Java程序之间交互的方式。在此之前,远程调用的方式主要是通过购买第三方产品(ORB)和编写Socket方式实现。
若不在Spring环境中使用RMI话,其主要涉及以下几个步骤:

  1. 编写一个服务实现类,该类中方法必须抛出java.rmi.RemoteException
  2. 编写一个继承 至java.rmi.Remote的服务接口
  3. 运行RMI编译器(rmic),创建客户端和服务端类
  4. 启动一个RMI注册表,以便持有这些服务
  5. 在RMI注册表中注册服务
    但在Spring使用则无须这么多步骤,得益于Spring的环境支撑,仅需要编写实现服务功能的POJO即可。
    Spring中使用RMI服务端主要代码如下:
public interface RemoteTestService {
    String say(String userName);
}
public interface RmiTestService extends RemoteTestService{

}
@Service
public class RmiTestServiceImp implements RmiTestService {
    @Override
    public String say(String userName) {
        return "hello," + userName + ",i am a RmiTestService";
    }
}
@Bean
    public RmiServiceExporter rmiServiceExporter(RmiTestService service) {
        RmiServiceExporter exporter = new RmiServiceExporter();
        exporter.setService(service);
        exporter.setServiceName("rmiTestService");
        exporter.setServiceInterface(RmiTestService.class);
        //注意,RMI方法需要绑定到某端口的注册表上,默认是1099
        exporter.setRegistryPort(9000);
        return exporter;
    }

服务端通过Spring的RmiServiceExporter将 RmiTestService 导出为一个RMI服务,并设置绑定注册表端口,以便于客户端访问RmiTestService 服务。

RMI方式客户端主要代码如下:

public static final String SERVER_URL = "127.0.0.1";

    @Bean
    public RmiProxyFactoryBean rmiProxyFactoryBean() {
        RmiProxyFactoryBean factoryBean = new RmiProxyFactoryBean();
        factoryBean.setServiceUrl("rmi://" + SERVER_URL + ":9000/rmiTestService");
        factoryBean.setServiceInterface(RmiTestService.class);
        return factoryBean;
    }
    public interface RemoteTestService {
    String say(String userName);
}
public interface RmiTestService extends RemoteTestService{

}
@RestController
@RequestMapping("rt")
public class RemoteTestController {
	@Autowired
    RmiTestService rmiTestService;
    @GetMapping("rmi")
    public String rmi(@RequestParam("userName") String userName) {
        return rmiTestService.say(userName);
    }
}

测试采用Swagger方式。测试结果如图:
在这里插入图片描述
RMI注意事项:

  1. 服务端和客户端必须保证是基于Java,且由于使用 了基于Java的序列化方式,因此双方的JDK版本必须一致。
  2. 服务端和客户端接口类相同
  3. 导出类不设置端口默认是1099端口
  4. 由于使用任意端口的问题,实际使用中会受到防火墙的限制,多用于内网环境下

Hessian和Burlab方式

Hessian 和 Burlab 是Caucho Technology提供的两种基于HTTP的轻量级远程服务解决方案。借助于尽可能简单的API和通信协议,致力于简化Web服务。
Hessian 与RMI类似,使用二进制进行客户端和服务端交互,但对比RMI方式来说又有些许不同,因为采用其自身的序列化化机制,Hessian产生的二进制消息可以移植到其他非Java的语言,如PHP、C等,只要Hessian支持该语言。
Burlab是一种基于XML方式的远程调用技术,可以轻松移植到能够解析XML方式的语言上 。且对比Hessian,因为XML的可读性比二进制强,但在带宽上Hessian方式更具优势。
在Spring中使用Hessian与RMI方式大同小异。
添加maven依赖:

  <dependency>
            <groupId>com.caucho</groupId>
            <artifactId>hessian</artifactId>
            <version>4.0.38</version>
        </dependency>

服务端主要代码:

 	@Bean(name = "/hessianServiceExporter")
    public HessianServiceExporter hessianExporter(HessianTestService hessianTestService) {
        HessianServiceExporter exporter = new HessianServiceExporter();
        exporter.setService(hessianTestService);
        exporter.setServiceInterface(HessianTestService.class);
        return exporter;
    }
	public interface HessianTestService extends RemoteTestService{
	
	}
	@Service
	public class HessianTestServiceImp implements HessianTestService {
	    @Override
	    public String say(String userName) {
	        return "hello," + userName + ",i am a HessianTestService";
	    }
	}

因为是基于HTTP实现的远程调用,因此需要在导出类中配置映射地址,以便客户端请求。
客户端主要代码:

	@Bean
    public HessianProxyFactoryBean hessianProxyFactoryBean() {
        HessianProxyFactoryBean factoryBean = new HessianProxyFactoryBean();
        factoryBean.setServiceUrl("http://" + SERVER_URL + ":8000/hessianServiceExporter");
        factoryBean.setServiceInterface(HessianTestService.class);
        return factoryBean;
    }
    
    @GetMapping("hessian")
    public String hessian(@RequestParam("userName") String userName) {
        return hessianTestService.say(userName);
    }

(此处不在放置测试结果)
注意事项:

  1. 需要引入第三方依赖
  2. Hessian和Burlab采用其私有的序列化机制,如果数据模型过于复杂,可能无法实现序列化

Spring 内置的HttpInvoker

Spring开发团队意识到RMI和基于HTTP(Hessian)的服务的空白(不足之处),一方面,RMI使用标准Java的序列化机制但由于其任意端口而无法越过防火墙,另一方面,Hessian虽然可以 很好穿透防火墙,但其使用其私有的序列化机制,使用中存在一些问题。因此Spring 的HttpInvoker应运而生,其取两者之长合一,使用简便。
其使用方法与Hessian方式类似,不做过多演示。
主要代码:

	 @Bean(name = "/httpInvokerServiceExporter")
	  public HttpInvokerServiceExporter httpInvokerServiceExporter(HttpInvokerTestService service) {
	        HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
	        exporter.setService(service);
	        exporter.setServiceInterface(HttpInvokerTestService.class);
	        return exporter;
	    }
	    @Bean
	    public HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean() {
	        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
	        factoryBean.setServiceUrl("http://" + SERVER_URL + ":8000/httpInvokerServiceExporter");
	        factoryBean.setServiceInterface(HttpInvokerTestService.class);
	        return factoryBean;
	    }

HttpInvoker由于其实Spring内置的,因此默认客户端、服务端双方皆是Spring应用,也即Java应用,且由于其采用Java的序列化机制,双方的JDK版本也必须保持一致。

JAX-WS方式

近年来SOA(面向服务架构)颇为流行,其核心理念:应用程序可以并且应该被设计成依赖于一组公共的核心服务,而不是为每个应用都重新实现相同的功能。
JAX可以发布基于平台独立的SOA服务,但代码设置较多,这里仅演示在Spring中快速开发SOA服务的方式。
服务端核心代码

	public interface Jax_wsTestService extends RemoteTestService {
	}
	@Service
	@WebService(serviceName="Jax_wsTestService",targetNamespace="http://Jax_wsTestService/service",name="Jax_wsTestService",portName="Jax_wsTestServicePort")
	public class Jax_wsTestServiceImp implements Jax_wsTestService {
	    @Override
	    public String say(String userName) {
	        return "hello," + userName + ",i am a Jax_wsTestService";
	    }
	
	}
 	 @Bean
    public SimpleJaxWsServiceExporter jaxWsServiceExporter() {
        SimpleJaxWsServiceExporter exporter=new SimpleJaxWsServiceExporter();
        //默认与当前应用使用相同路径,即http://127.0.0.1:8000/
        exporter.setBaseAddress("http://127.0.0.1:8002/services/");
        return exporter;
    }
      @Bean
    public JaxWsPortProxyFactoryBean jaxWsPortProxyFactoryBean()throws Exception{
        JaxWsPortProxyFactoryBean jaxProxy=new JaxWsPortProxyFactoryBean();
        jaxProxy.setWsdlDocumentUrl(new URL("http://localhost:8002/services/Jax_wsTestService?wsdl"));
        jaxProxy.setServiceInterface(Jax_wsTestService.class);
        //命名空间,服务名等可从service上的注解指定
        return jaxProxy;
    }

在需要导出的服务上通过WebService注解指明导出服务类
的命名空间、服务名等信息,仅需要配置一个简单的导出类,其会自动将含Jax注释的类导出。

相关代码:
github链接 https://github.com/junxiaoyao/springStudy.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值