接口开发 — — RPC远程过程调用实现

末蓝、 2024-04-06 12:26 227阅读 0赞

接口开发 — — RPC远程过程调用实现

我们在日常开发过程中,经常会遇到与第三方交互的情况,这个时候就会涉及到RPC(Remote Procedure Call)远程过程调用。

比如下表:
在这里插入图片描述
其实,这就涉及到RPC的实现了,那么什么是RPC呢?RPC又是怎么实现的呢?

1 介绍

RPC(Remote Procedure Call):远程过程调用,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。请求程序就是一个客户端,而服务提供程序就是一个服务器。
在这里插入图片描述

2 应用场景

支付宝、微信、银联等第三方支付接入

3 实现方式

3.1 RMI

RMI:Java提供的基于Java平台的RPC远程调用技术,服务消费者和服务提供者是Java平台。

在这里插入图片描述

3.1.1 RMI实现步骤

新建rmi-provider项目

结构图:
在这里插入图片描述

3.1.1.1 创建UserService接口

用于提供服务;实现接口时,需要抛出异常【强制】

  1. /**
  2. * 创建需要发布的服务对应的业务接口
  3. * Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口
  4. */
  5. public interface UserService extends Remote {
  6. public String helloRMI(String name) throws RemoteException;
  7. }
3.1.1.2 创建UserServiceImpl实现类

一定要继承UnicastRemoteObject类,不然会发布失败

  1. /**
  2. * 创建发布的服务对应的实现类
  3. */
  4. public class UserServiceImpl extends UnicastRemoteObject implements UserService {
  5. public UserServiceImpl() throws RemoteException {
  6. super();
  7. }
  8. @Override
  9. public String helloRMI(String name) {
  10. return "hello:" + name;
  11. }
  12. }
3.1.1.3 发布远程服务【ProviderApp】
  1. /**
  2. * 发布远程服务
  3. */
  4. public class ProviderApp {
  5. public static void main(String[] args) {
  6. try {
  7. //发布服务的端口
  8. LocateRegistry.createRegistry(8888);
  9. //发布远程服务的URL
  10. String name = "rmi://localhost:8888/rmi";
  11. //创建一个提供具体服务的远程对象
  12. UserService userService = new UserServiceImpl();
  13. //给提供远程服务的对象绑定一个URL
  14. Naming.bind(name, userService);
  15. System.out.println("发布RMI远程服务成功");
  16. } catch (Exception e) {
  17. System.out.println("发布失败.....");
  18. e.printStackTrace();
  19. }
  20. }
  21. }

结果:
在这里插入图片描述

3.1.1.4 服务消费者实现【拷贝UserService接口】

创建rmi-consumer项目

项目结构:
在这里插入图片描述

  1. //从服务提供端拷贝来的接口【与远程服务提供方保持一致】
  2. public interface UserService {
  3. public String helloRMI(String name);
  4. }
3.1.1.5 消费远程服务【ConsumerApp】
  1. import java.rmi.Naming;
  2. //消费远程服务
  3. public class ConsumerApp {
  4. public static void main(String[] args) {
  5. try {
  6. //访问远程服务的URL
  7. String name = "rmi://localhost:8888/rmi";
  8. //通过发布的远程服务的URL,获得远程服务的代理对象
  9. UserService userService = (UserService) Naming.lookup(name);
  10. System.out.println("获得远程服务的代理对象" + userService.getClass().getName());
  11. //通过远程服务的代理对象调用远程服务的方法
  12. String result = userService.helloRMI("jack");
  13. System.out.println("result:" + result);
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }

结果:
在这里插入图片描述

3.1.2 RMI实现过程的常见错误

java的 rmi远程调用给分布式编程带来极大的方便,在使用rmi过程中若遇到以下两个问题,可以尝试如下的解决方法

  • 错误一:

    java.rmi.server.ExportException : remote object implements illegal remote
    interface; nested exception is : java.lang.IllegalArgumentException :
    illegal remote method encountered : ,

    “解决办法”:如果这样提示说明接口函数没有涉及异常抛出,在所提示的函数后面加
    上throws RemoteException就可以解决

  • 错误二:

    exception: java.rmi.UnmarshalException: error unmarshalling return; nested
    exception is: java.io.WriteAbortedException: writing aborted;
    java.io.NotSerializableException :

    “解决办法”:若这样提示,表明某个类是不能被序列化的,需要在该类上加上implements
    Serializable,就可以解决

需要注意的是,Java的RMI远程调用的两个站点可能需要编写相同的代码,保证不提示什么错误,就可以正常运行

3.1.3 RMI总结

























名称 含义
Remote接口 标识某个方法可以被远程调用
UnicastRemoteObject类 实现Remote远程对象的导出
Naming 给提供远程服务的对象绑定URL,通过远程的URL,获得提供远程服务的代理对象
LocateRegistry类 指定发布的远程服务的方法接口

实现步骤:
①创建服务接口
②实现接口内容【具体服务内容】
③发布服务
④消费方拷贝服务接口
⑤消费方消费远程服务

3.2 WebService【http+xml】

3.2.1 定义

通过Http协议,请求发送XML和响应XML的RPC远程调用技术,最大的特征就是使用XML进行数据交互,可以实现跨平台调用。

WebService也叫XML Web Service,WebSerice是一种可以接收从Internet或者Intranet上的其他系统中传递过来的请求,轻量级的独立的通讯服务。是通过SOAP在Web上提供对的软件服务,使用WSDL文件进行说明,并通过UUDI进行注册。

总的来说,WebService就是一种跨编程语言和操作系统平台的远程调用技术

从多个维度理解WebService:

  • 从表面看:WebService就是一个应用程序向外界暴露出一个能够通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个程序。【调用这个WebService的应用程序叫做客户端;提供这个WebService的应用程序叫做服务端】
  • 从深层次看:WebService是建立可交互操作的分布式应用程序的新平台,是一个平台,一套标准。它定义了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写WebService,只要我们可以通过WebService标准对这些服务进行查询和访问。

在这里插入图片描述

拓展:【WebSocket】
WebSocket是H5支持的新特性,WebSocket他是为了解决客户端发起多个http请求到服务器资源浏览器必须要经过长时间的轮训问题而生的,他实现了多路复用,他是全双工通信。在webSocket协议下客服端和浏览器可以同时发送信息。

  • WebService:实现RPC
  • WebSocket:实现多路复用
3.2.2 核心要素【SOAP、WSDL、UDDI】

SOAP、WSDL、UDDI(UniversalDescriptionDiscovery andIntegration)三者构成了WebService的三要素。

  • SOAP(Simple Object Access Protocol):

    WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果都是采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML格式就是SOAP协议。SOAP提供了标准的RPC方法来调用WebService。

    SOAP协议组成:
    SOAP协议 = HTTP协议+XML数据格式

    SOAP协议定义了SOAP消息的格式,SOAP协议是基于HTTP协议的,SOAP也是基于XML和XSD的,XML是SOAP的数据编码方式。打个比喻就是:HTTP是普通公路,XML是中间的绿色隔离带和两边的防护栏,SOAP就是普通公路经过隔离带和防护栏改造过的高速公路。

  • WSDL
    就像是我们区商店买东西,首先要知道商店里有什么东西可以买,然后再来购买。商家的做法就是张贴海报。WebService也一样,WebSerive客户端要调用一个WebSerivce服务,首先要知道这个服务的地址在哪,以及这个服务里有什么方法可以调用。所以,WebService服务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受的参数是什么,返回值是什么),服务的网络地址用哪个URL地址表示,服务通过什么方式来调用。

    WSDL(Web Services Description Language)就是这样一个基于XML的语言,用于描述WebService及其函数、参数、返回值。它是WebService客户端和服务端都能理解的标准格式。因为是基于XML的,所以WSDL既是机器可读的,又是人可阅读的,这是一个很大的好处。【一些开发工具可以根据我们的WebService生成WSDL文档,又可以导入WSDL文档,生成调用相应的WebService的代理类代码】。

  • UDDI
    UDDI(Universal Description, Discover, and Integeration)是一个主要针对Web服务供应商和使用者的新项目。在用户能够调用Web服务之前,必须确定这个服务内包含哪些方法,找到调用的接口的定义,还要在服务端来编制软件,UDDI是一种根据描述文档来以电脑系统查找相应服务的机制。
    UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,编辑,浏览以及查找注册信息。它采用XML格式来封装各种不同类型的数据,并且发送到注册中心或由注册中心来返回需要的数据。
3.2.3 调用原理

在这里插入图片描述
实现一个完整的Web服务工作流程:

  1. 【注册】Web服务提供者设计实现Web服务,并将调试正确后的Web服务通过Web服务中介者发布,并在UDDI注册中心注册
  2. 【请求服务】Web服务请求者向Web服务中介者请求特定的服务,中介者根据请求查询UDDI注册中心,为请求者寻找满足请求的服务
  3. 【返回服务描述信息】Web服务中介者向Web服务请求者返回满足条件的Web服务描述信息,该信息用WSDL写成,各种支持Web服务的机器都能阅读。
  4. 【发送SOAP消息】利用从Web服务中介者返回的描述信息生成相应的SOAP消息,发送给Web服务提供者,以实现Web服务调用
  5. 【返回执行结果】Web服务提供者按SOAP消息执行相应的Web服务,并将服务结果返回给Web服务请求者
3.2.4 使用场景
  1. "适用范围":应用程序跨平台、跨网络。适用于应用程序集成B2B集成、代码和数据重用以及通过
  2. Web进行客户端和服务器通信的场合。
  3. "不适用场景"WebService会降低应用程序的性能,因此一台机器或者局域网里面运行的同构应用
  4. 程序就不应该用Web Service进行通信

详细说明:https://blog.csdn.net/weidawei0609/article/details/7915071

3.2.5 实现步骤

创建服务提供方ws_server项目

服务端结构:
在这里插入图片描述

3.2.5.1 创建WeatherService接口【创建服务端】
  1. /**
  2. * 天气服务接口
  3. */
  4. @WebService
  5. public interface WeatherService {
  6. @WebMethod
  7. String getWeatherByCityName(String name);
  8. }
3.2.5.2 创建WeatherService接口实现类
  1. //创建服务实现类
  2. @WebService
  3. public class WeatherServiceImpl implements WeatherService {
  4. @Override
  5. public String getWeatherByCityName(String name) {
  6. return name + "今天艳阳高照!!!";
  7. }
  8. }
3.2.5.3 发布天气服务
  1. //发布天气
  2. public class Main {
  3. public static void main(String[] args) {
  4. //发布天气服务【这里只是简单的进行测试】
  5. Endpoint.publish("http://localhost:8085/test_server/weather",
  6. new WeatherServiceImpl());
  7. System.out.println("发布天气服务成功...");
  8. }
  9. }

在这里插入图片描述

至此,服务端程序创建发布成功,运行后可在浏览器中访问http://localhost:8085/test_server/weather?wsdl
在这里插入图片描述
可以看到,我们的服务已经发布成功了。
在这里插入图片描述

3.2.5.4 创建客户端,在cmd窗口运行命令

创建客户端项目

  1. 生成客户端代码有很多种方式,这里我们演示JDL自带的wsimport工具
  • 运行命令前:
    在这里插入图片描述
  • 运行命令

    选中src,鼠标右键,选择Open in terminal打开cmd,当然,我们也可以win+R输入cmd,
    打开dos命令,进入到ws_client项目的src目录。

输入wsimport -keep http://localhost:8085/test_server/weather?wsdl,点击回车,出现下图情况即为生成成功。
(还可以将wsimport -keep http://localhost:8085/test_server/weather?wsdl生成的文档以wsdl为后缀保存到项目中,输入wsimport -keep wsdl文件的路径执行)
在这里插入图片描述

  • 运行结果
    在这里插入图片描述
3.2.5.5 客户端调用服务端
  1. /**
  2. * WebService客户端测试
  3. */
  4. public class ClientTest {
  5. public static void main(String[] args) {
  6. //创建服务类对象
  7. WeatherServiceImplService service = new WeatherServiceImplService();
  8. //创建远程服务的代理对象
  9. WeatherServiceImpl weatherService = service.getWeatherServiceImplPort();
  10. System.out.println(weatherService.getClass().getName());
  11. //进行远程服务调用
  12. String weather = weatherService.getWeatherByCityName("杭州");
  13. System.out.println(weather);
  14. }
  15. }

运行结果:
在这里插入图片描述

3.2.6 总结





















名称 作用
@WebService 指定发布远程的服务(默认类中的所有方法)
@WebMethod 指定类中特定的方法发布远程服务
EndPoint 发布具体的远程服务,给提供远程服务的对象绑定一个URL

3.3 HttpClient【http+json】

HttpClient:Http客户端工具,Java程序通过HttpClient发送Http协议的请求,直接获得远程资源。

在这里插入图片描述

3.3.1 定义

就目前来说,HTTP协议是在Internet上使用得最多、最重要的协议的了,越来越多的Java应用程序需要直接通过HTTP协议来访问网络资源。

HttpClient是Apache Jakarta Common下的子项目,提供了高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包。实现了所有HTTP的方法(GET、POST、PUT、HEAD等八种),支持RestFul。
在这里插入图片描述

3.3.2 实现步骤
3.3.2.1 创建服务端【Controller层】
  1. @Controller
  2. public class DemoController {
  3. @RequestMapping("/demo")
  4. @ResponseBody
  5. public String demo(String param){
  6. return "demo" + param;
  7. }
  8. }

服务端启动类:

  1. @SpringBootApplication
  2. public class HttpClientServerApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(HttpClientServerApplication.class, args);
  5. }
  6. }
3.3.2.2 创建客户端【导入httpClient依赖】

导入依赖:

  1. <!--导入依赖:httpClient-->
  2. <dependency>
  3. <groupId>org.apache.httpcomponents</groupId>
  4. <artifactId>httpclient</artifactId>
  5. <version>4.5.10</version>
  6. </dependency>
3.3.2.3 GET方式请求
  1. public class GetDemo {
  2. public static void main(String[] args) {
  3. try{
  4. //创建http工具(理解成:浏览器) 发起请求,解析响应
  5. CloseableHttpClient httpClient = HttpClients.createDefault();
  6. //请求路径
  7. URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/demo");
  8. uriBuilder.addParameter("param", "get123");
  9. //创建HttpGet的请求对象
  10. HttpGet get = new HttpGet(uriBuilder.build());
  11. //创建响应对象
  12. CloseableHttpResponse response = httpClient.execute(get);
  13. //由于响应体是字符串,因此把HttpEntity类型转换为字符串类型,并设置字符编码
  14. String result = EntityUtils.toString(response.getEntity(), "utf-8");
  15. //输出结果
  16. System.out.println(result);
  17. //释放资源[可以提到finally中释放]
  18. response.close();
  19. httpClient.close();
  20. } catch (URISyntaxException e) {
  21. e.printStackTrace();
  22. } catch (ClientProtocolException e) {
  23. e.printStackTrace();
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

在这里插入图片描述

3.3.2.4 POST方式请求
  1. public class PostDemo {
  2. public static void main(String[] args) {
  3. try{
  4. //创建Http工具(相当于:浏览器) 发起请求,解析响应
  5. CloseableHttpClient httpClient = HttpClients.createDefault();
  6. //创建HttpPOST对象
  7. HttpPost post = new HttpPost("http://localhost:8080/demo");
  8. //所有请求参数
  9. ArrayList<NameValuePair> params = new ArrayList<>();
  10. params.add(new BasicNameValuePair("param", "123"));
  11. //创建HttpEntity接口的文本实现类对象,放入参数并设置编码
  12. HttpEntity httpEntity = new UrlEncodedFormEntity(params, "utf-8");
  13. //放入到HttpPost对象中
  14. post.setEntity(httpEntity);
  15. //创建响应对象
  16. CloseableHttpResponse response = httpClient.execute(post);
  17. //由于响应体是字符串,因此把HttpEntity类型转换为字符串类型
  18. String result = EntityUtils.toString(response.getEntity());
  19. //输出结果
  20. System.out.println(result);
  21. //释放资源[一般是在finally里释放]
  22. response.close();
  23. httpClient.close();
  24. } catch (UnsupportedEncodingException e) {
  25. e.printStackTrace();
  26. } catch (ClientProtocolException e) {
  27. e.printStackTrace();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

在这里插入图片描述

参考文章:
https://blog.csdn.net/qq\_34845394/article/details/86478208
https://www.jb51.net/article/225494.htm

发表评论

表情:
评论列表 (有 0 条评论,227人围观)

还没有评论,来说两句吧...

相关阅读