开发者学堂课程【Scala 核心编程 - 进阶:RMI 的介绍和应用实例】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/610/detail/9145
RMI 的介绍和应用实例
内容介绍:
一、完成远程监控糖果机
二、讲解 Java RMI
三、总结回顾
一、完成远程监控糖果机
1.问题引入
本地监控完成之后我们需要要研究一个问题,如何完成糖果机的远程监控,假如现在糖果机不在本地,而是在北京,此时我们工程师使无法达到现场,体系里面每一个地区一般都有一台自己的服务器,各个省份将数据提交到总服务器,总部如何来远程监控其他省份的或者是海外的糖果机,就是一个问题。
因为各地的网络可能根本不一样,比如北京具有10台糖果机,纽约有20台糖果机,无法做到直接调用,而他们的网络并不一样,因此完成远程调用就会相对麻烦一些。
2、具体分析
方式1:因为远程机不在本地,可能在另外的城市或者国家,这时可以使用socket编程来进行网路编程控制,缺点是比较麻烦。
方式2:在远程放置web服务器,通过web编程来实现远程监控,但是安全性不够高。
方式3:可能会提到之前所学的阿卡也可以用于远程调用,但是或多或少还是会存在一些问题的,因此使用并不广泛。
方式4:使用 RMI(Remote Method Invocation)远程方法,学习Java的时候,可能会讲到 RMI,RMI 在之前时代是非常火的,现在大多在代理模式上有一些应用,其他方面的用途逐渐退化了,有了更为先进的方式来替代它的功能,调用来完成对远程糖果机的监控。远程监控时之所以用到RMI是因为RMI将socket的底层封装起来,对外提供调用方法接口即可,这样比较简单,这样我们就可以实现远程代理模式开发。
3、远程代理
图示中左侧为本地的监控,右侧为远程的机器,使用 Agent 来实现对 Machine 的调用。简单来说,远程代理就是远程对象的本地代表 Agent,使用 RMI 来完成系列操作,通过它可以把远程对象当本地对象来调用,远程代理通过网络和真正的远程对象沟通信息。
4、实现远程代理的核心技术—Java RMI
若要实现上述的远程调用需要一个核心技术,即 java RMI 技术,RMI 指的是远程方法调用(Remote Method Invocation)。
它是一种机制,能够让在某个Java虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。底层其实就是上层编程,本地的 Monitor RMI的STUB树根与远程的RMI SKELET 槽之间可以无缝插入接轨,SKELET与Machine进行交互,再把结果返回到本地。可以用此方法调用的任何对象必须实现该远程接口,RMI可以将底层的socket编程封装,简化操作。
二、讲解 Java RMI
1、Java RMI 的介绍
左侧为本地端(本地程序),右侧为远程端(远程程序),远程程序具有一个 SayHello 的方法,该方法实现的功能很简单,可以输出 hello word,现在本地端有一个deftest的方法,希望可以调用远程端的 SayHello 方法,要实现这种效果并不简单,不能通过简单的一个阿卡来解决。
现在需要直接实现远程方法调用,这和阿卡是有区别的,阿卡是发送消息之后,这个消息告诉本地去做一件事,在本地实现调用然后将结果返回。RMI可以实现把远程在本地登录,作为一个程序还是应该知道这种技术,这种技术又叫做ejb,在前些年这项技术是非常厉害的。
- RMI远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制。
- 使用RMI机制,一台计算机上的对象可以调用另外一台计算机上的对象来获取远程数据。
- RMI被设计成一种面向对象开发方式,允许程序员使用远程对象来实现通信。与之对应的面向过程的方法叫做RPC,没有RMI的功能强大
2、Java RMI 的开发应用案例说明
要求:请编写一个JavaRMI的案例,代理端(客户端)可以通过rmi远程调用远程端注册的一个服务的sayHello的方法,并且返回结果。
- 开发步骤
首先制作远程端的接口,开发一个接口以后在远程端实现Service文件并完成一个方法注册,其实就是把SayHello方法注册到体系中去,注册完成之后RMI就可以调用了。
- 开发示意图
远程端(服务器端),先写一个MyremoteImpl.scala实例,用Myremote实现接口里面的方法SayHello,远程端里面写代码注册,然后将接口文件给到客户端(代理端),因此接口文件很重要,会拷贝两份,通过远程先把接口程序打包给到服务器端,再打包给到代理端,和我们前面讲到的内容很相似。
通过RMI远程调用远程端注册的服务,它是以一种服务的形式来提供的,类似于打电话通过移动或者联通提供服务,该服务需要实现接口SayHello,远程端返回SayHello方法。
调完之后远程端返回结果,这个功能十分厉害,可以直接返回方法,不像阿卡是发送消息,待消息执行完毕后将结果返回。
- 代码实现
1.通过示意图我们知道共有三个文件,第一个文件是接口,这个接
口用来写入SayHello方法或者更多的方法,甚至实现远程调用对方数据库的功能,新建一个接口MyRemote,接口里的方法可以根据需要确定,可供本地和客户端使用,
代码如下:
package com.atguigu.chapter17.rmi
import java.rmi .{Remote,RemoteException}
trait MyRemote extends Remote{
@throws(classof[RemoteException])
def sayHe1lo():string //throws RemoteException
}
需要注意的是代码的写入需要按照确定的流程,代码抛出的异常一定要写出,否则该程序无法运行。案例代码中写入了一个抽象方法。
2.第二个文件是远程端MyremoteImpl.scala的写入,新建一个
scala class,命名为MyremoteImpl,具体代码为:
package com.atguigu.chapter17.rmi
class MyRemoteImpl extends unicastRemoteobject with MyRemote {@throws(classof[RemoteException])
override def sayHe11o(): string = {
"Hello wor1d!~"
}
}
object MyRemoteImpl {
def main(args : Array[string]):Unit = {
val service: MyRemote = new MyRemoteImpl()
//准备把服务绑定到9999端口
/LocateRegistry.createRegistry ( 9999)
//Naming.rebind( "RemoteHeLlo", service)
Naming.rebind("rmi://127.0.8.1:9999/RemoteHello", service)
println("远程服务开启,在127.0.0.1 的 9999端口监听,服务名RemoteHello")
}
}
代码解释:
1.class MyRemoteImpl extends unicastRemoteobject with
MyRemote {@throws(classof[RemoteException])
override def sayHe11o(): string = {
"Hello wor1d!~"
}
}
这段代码实现了 MyRemote 接口(trait)
2.object MyRemoteImpl {
def main(args : Array[string]):Unit = {
val service: MyRemote = new MyRemoteImpl()
//准备把服务绑定到9999端口
//LocateRegistry.createRegistry ( 9999)
//Naming.rebind( "RemoteHeLlo", service)
Naming.rebind("rmi://127.0.8.1:9999/RemoteHello", service)
println("远程服务开启,在127.0.0.1 的 9999端口监听,服务名RemoteHello")
}
}
这一段代码实现了对服务(SayHello)注册任务,对服务进行管理,如果只写入而不注册上去别人不能知道你的方法,这个注册的主要目的就是RMI的地址跟Naming绑定。
注册过程中可能会出现一些小差错,因此我们提供了两种注册方式,第一种注册方式是:
//准备把服务绑定到9999端口
//LocateRegistry.createRegistry ( 9999)
//Naming.rebind( "RemoteHeLlo", service)
第二种注册方式是:
Naming.rebind("rmi://127.0.8.1:9999/RemoteHello", service)
如果你第一种方式不好用,可以选择第二种注册方式,因为有的机器的底层系统不一样,这跟底层的操作系统有关系。
将来RemoteHello就是一个服务,他指向了Service,而这个Service指向了MyRemoteImp,而MyRemoteImp又指向了SayHello,因此服务里面到底有多少方法取决于写入了多少方法,如果有多种方法,那该服务就代表多个方法。
运行起来之后可以看到报错,说明使用方式二的注册方法不可行,因此我们换成方式一进行注册,仍然显示出错,通过检查将格式调整后运行成功,显示远程服务开启,在127.0.0.1的9999端口监听,服务名 RemoteHello 。
- 现在开始写入第三个文件,远程客户端的代码非常简单,我们看
一下是如何使用的即可。
代码如下:
class MyRemoteClient {
def go()= {
val service=Naming.lookup("rmi:l/127.0.0.1:9999/RemoteHello").
asInstanceOf[MyRer
val str = service.sayHello()
println("str = " +str)
}}
object MyRemoteClient {
def main(args: Array[String]): Unit ={
new MyRemoteClient().go()
}}
使用Naming. Lookup,Naming是命名符,通过lookup找到了远程服务,把转成了接口结构,然后就可以调用了,相当于通过命名服务找到注册的Service,然后Servive里的任何方法都可以使用了,而Service里的方法是通过文件二写入的。最后通过
MyRemoteClient创建了一个对象就可以了。运行观察远程服务有没有被调用起来,程序跑完之后显示str= Hello World 。
3、用RMI来解决代理模式
我们之所以讲刚刚的案例,是为了更好地讲解远程代理,因为远程代理的核心就用RMI。
三、总结回顾
1、代理模式的基本概念
代理模式:为一个对象提供一个替身,以控制对这个对象的访问
被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象,安全控制的对象一般通过动态代理来实现。
代理模式有不同的形式(比如远程代理,静态代理,动态代理),都是为了控制与管理对象访问
2、糖果机案例—看一个项目需求
糖果机项目的具体要求如下:
1.某公司需要将销售糖果的糖果机放置到本地(本地监控)和外地(远程监控),进行糖果销售。
2.给糖果机插入硬币,转动手柄,这样就可以购买糖果。
3.可以监控糖果机的状态和销售情况。
3、完成监控远程糖果机
说明:对远程糖果机的状态和销售情况进行监控,相对麻烦些,我们先分析一下
方式1:因为远程糖果机不在本地,比如在另外的城市,国家,这时可以使用socket编程来进行网络编程控制(缺点:麻烦)
方案2:在远程放置web服务器,通过web编程来实现远程监控。
方案3:使用RMI(Remote Method Invocation)远程方法调用来完成对远程糖果机的监控,因为RMI将socket的底层封装起来,对外提供调用方法接口即可,这样比较简单,这样我们就可以实现远程代理模式开发。
4、远程代理模式监控方案
远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信息。
涉及到一个核心技术RMI
5、Java RMI 实现远程代理
RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个Java虚拟机上的对象调用另一个 Java虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口,RMI可以将底层的socket编程封装,简化操作。
6、Java RMI的介绍
一共总结了三点:
- RMI远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制。
- 使用RMI机制,一台计算机上的对象可以调用另外一台计算机上的对象来获取远程数据。
- RMI被设计成一种面向对象开发方式,允许程序员使用远程对象来实现通信。与之对应的面向过程的方法叫做RPC,没有RMI的功能强大
7、 Java RMI 的开发应用案例说明
要求:请编写一个JavaRMI的案例,代理端(客户端)可以通过rmi远程调用远程端注册的一个服务的sayHello的方法,并且返回结果。
8、Java RMI 的开发应用案例-开发步骤
1)制作远程接口:接口文件
2)远程接口的实现:Service文件
3) RMI服务端注册,开启服务
4)RMI代理端通过RMI查询到服务端,建立联系,通过接口调用远程方法
9、Java RMI 的开发应用案例-程序框架
10、Java RMI 的开发应用案例-代码实现