• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
NPE~
帮助1

接口开发 — — 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接口

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

/**
 * 创建需要发布的服务对应的业务接口
 * Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口
 */
public interface UserService extends Remote {

    public String helloRMI(String name) throws RemoteException;
}
3.1.1.2 创建UserServiceImpl实现类

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


/**
 * 创建发布的服务对应的实现类
 */
public class UserServiceImpl extends UnicastRemoteObject implements UserService {
    
    public UserServiceImpl() throws RemoteException {
        super();
    }
    
    @Override
    public String helloRMI(String name) {
        return "hello:"   name;
    }
}
3.1.1.3 发布远程服务【ProviderApp】
/**
 * 发布远程服务
 */
public class ProviderApp {
    public static void main(String[] args) {
        try {
            //发布服务的端口
            LocateRegistry.createRegistry(8888);
            //发布远程服务的URL
            String name = "rmi://localhost:8888/rmi";
            //创建一个提供具体服务的远程对象
            UserService userService = new UserServiceImpl();
            //给提供远程服务的对象绑定一个URL
            Naming.bind(name, userService);
            System.out.println("发布RMI远程服务成功");
        } catch (Exception e) {
            System.out.println("发布失败.....");
            e.printStackTrace();
        }
    }
}
学新通

结果:
学新通

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

创建rmi-consumer项目

项目结构:
学新通

//从服务提供端拷贝来的接口【与远程服务提供方保持一致】
public interface UserService {
    
    public String helloRMI(String name);
}
3.1.1.5 消费远程服务【ConsumerApp】
import java.rmi.Naming;

//消费远程服务
public class ConsumerApp {

    public static void main(String[] args) {
        try {
            //访问远程服务的URL
            String name = "rmi://localhost:8888/rmi";
            //通过发布的远程服务的URL,获得远程服务的代理对象
            UserService userService = (UserService) Naming.lookup(name);
            System.out.println("获得远程服务的代理对象"   userService.getClass().getName());
            //通过远程服务的代理对象调用远程服务的方法
            String result = userService.helloRMI("jack");
            System.out.println("result:"   result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
学新通

结果:
学新通

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 使用场景
"适用范围":应用程序跨平台、跨网络。适用于应用程序集成B2B集成、代码和数据重用以及通过
Web进行客户端和服务器通信的场合。
"不适用场景":WebService会降低应用程序的性能,因此一台机器或者局域网里面运行的同构应用
程序就不应该用Web Service进行通信

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

3.2.5 实现步骤

创建服务提供方ws_server项目

服务端结构:
学新通

3.2.5.1 创建WeatherService接口【创建服务端】
/**
 * 天气服务接口
 */
@WebService
public interface WeatherService {

    @WebMethod
    String getWeatherByCityName(String name);
}
3.2.5.2 创建WeatherService接口实现类
//创建服务实现类
@WebService
public class WeatherServiceImpl implements WeatherService {


    @Override
    public String getWeatherByCityName(String name) {
        return name   "今天艳阳高照!!!";
    }
}
3.2.5.3 发布天气服务
//发布天气
public class Main {
    public static void main(String[] args) {
        //发布天气服务【这里只是简单的进行测试】
        Endpoint.publish("http://localhost:8085/test_server/weather", 
        	new WeatherServiceImpl());
        System.out.println("发布天气服务成功...");
    }
}

学新通

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

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

创建客户端项目

生成客户端代码有很多种方式,这里我们演示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 客户端调用服务端
/**
 * WebService客户端测试
 */
public class ClientTest {

    public static void main(String[] args) {
        //创建服务类对象
        WeatherServiceImplService service = new WeatherServiceImplService();
        //创建远程服务的代理对象
        WeatherServiceImpl weatherService = service.getWeatherServiceImplPort();
        System.out.println(weatherService.getClass().getName());
        //进行远程服务调用
        String weather = weatherService.getWeatherByCityName("杭州");
        System.out.println(weather);
    }
}
学新通

运行结果:
学新通

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层】
@Controller
public class DemoController {

    @RequestMapping("/demo")
    @ResponseBody
    public String demo(String param){
        return "demo"   param;
    }

}

服务端启动类:

@SpringBootApplication
public class HttpClientServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(HttpClientServerApplication.class, args);
    }

}
3.3.2.2 创建客户端【导入httpClient依赖】

导入依赖:

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

学新通

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

学新通

学新通

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgcbjab
系列文章
更多 icon
同类精品
更多 icon
继续加载