方法的调用都是发生在相同堆上的两个对象之间(同一台机器的Java虚拟机),如果想要调用另一台机器上的对象,可以通过Socket进行输入/输出。
远程过程调用需要创建出4种东西:服务器、客户端、服务器辅助设施、客户端辅助设施
 
RMI
Java的JMI提供客户端和服务器端的辅助设施对象(stub和skeleton,现在实际只用stub文件,客户端和服务端用一个)
辅助设施是实际执行通信的对象,他会让客户端感觉在调用本机,实际上辅助设施类似于代理,将客户端传送的信息通过Socket连接发送给服务端辅助设施,然后服务端辅助设施解包调用真正的服务端的服务,服务辅助设施取得结果后将他通过Socket连接返回给客户端辅助设施,客户端辅助设施解开这些信息传给客户端
 
远程的服务调用是通过java.rmi.registry来实现的。它提供了RMI注册表的一个类和两个接口,注册表绑定字符串名称和远程对象,可以通过注册表调用远程服务的某个对象
 
服务器端的service实现了远程调用的真正方法
 
Client辅助设施和Service辅助设施是同一个文件,在服务器端生成的
 
创建远程服务
 
大致步骤如下图所示:
 
步骤1:创建Remote接口
定义客户端会调用的方法,stub和服务都会实现此接口。远程接口定义了客户端可以远程调用的方法。
 
import java.rmi.*;
public interface MyRemote extends Remote{
     public String sayHello() throws RemoteException;
}
 
说明:
1.接口必须继承Remote
2.远程调用是有风险的,需要通过抛出一个RemoteException异常强迫客户端注意到这件事
3.远程方法的参数和返回值必须是primitive或Serializable的
 
步骤2:实现Remote接口
这个是真正执行的类,实现接口上的方法,也是客户端会调用的对象,去执行真正的工作
public class MyRemoteImp1 extends UnicastRemoteObject implements MyRemote{
     public MyRemoteImp1() throws RemoteException{}//UnicastRemoteObject会抛出RemoteException异常,构造函数抛出同样异常
     public String sayHello(){//实现Remote接口的所有方法
          return "Server says,‘Hey’"
     }
}
 
说明:
1.实现Remote的接口
2.要有与远程有关的功能,可以继承UnicastRemoteObject(UnicastRemoteObject 会抛出RemoteException异常,如果调用需要构造函数也抛出同样的异常)
3.向RMI registry注册服务
只有向RMI registry注册了,才能让远程用户存取(一定要RMI registry一定要注册起来否则运行程序会失败),注册对象时RMI 会把stub加到registry中,这是客户端需要的,使用java.rmi.Naming的rebind()注册服务
try{
     MyRemote service=new MyRemoteIm1();
     Naming.rebind("Remote Hello",service);//将实现的接口类实例向RMI registry注册,帮服务命名(Remote Hello)
}catch(Exception ex){...}
 
 
步骤3:用rmic产生stub
对真正实现的类执行rmic,产生helper类(stub)
会按照命名规则在远程实现的名称后加上_Stub。
rmic MyRemoteImp1
会生成MyRemoteImp1_Stub.class文件
 
 
步骤4:启动RMI registry(rmiregistry)
用户会从此处获得代理(客户端的sub/helper对象)
需要在实现的服务类下去执行命令:rmiregistry
如果想指定端口号,可以通过【rmiregistry 端口号】来启动
 
步骤5:启动远程服务
【java 真正实现的类】启动服务,实现服务的类的实例会向RMI registry注册(注册后才能对用户提供服务)
java MyRemoteImp1
 
指定服务端口号
两种方法:一是程序中指定,二是启动rmiregistry时指定
程序中指定:
 
启动rmiregistry指定:【rmiregistry 端口号】
 
客户端实现
 
客户端获得stub对象
直接将服务器上生成的stub文件拷贝到客户端上即可
 
客户端调用远程方法
通过Naming.lookup()的静态方法寻找某台IP上注册的远程方法(通过Naming.rebind()注册),返回一个stub对象
MyRemote service=(MyRemote) Naming.lookup("rmi://127.0.0.1:服务端口号/Remote Hello");
 
如果Naming.lookup没有指定服务的端口号,则用java默认的1099端口号
 
说明:
1.客户端调用服务必须与服务端使用相同的接口类型
2.Naming.lookup()寻址的格式【rmi://服务器地址/注册的远程方法名】,返回一个stub对象
3.客户端本地一定要有服务端rmic产生的stub类,否则RMI registry返回的stub对象不会被解序列化
 
 
RMI的注意事项
1.在启动远程服务前(java 实现服务的类),必须先启动rmiregistry
2.参数和返回类型必须是可序列化的
3.将stub类交给客户端
4.客户端和服务端一定要能够ping通,否则不能调用
 
遇到的问题
问题:
客户端启动时提示地址非法:java.net.MalformedURLException: invalid URL String: rmi://127.0.0.1:2000/Remote Hello
 
解决方法:
将远程的服务地址转换一下编码格式
String url="rmi://127.0.0.1:2000/Remote Hello";
url= URLEncoder.encode(url, "UTF-8");
MyRemote service=(MyRemote) Naming.lookup(url);
 
 
 

java基础十一[远程部署的RMI](阅读Head First Java记录)的更多相关文章

  1. java基础四 [构造器和垃圾回收](阅读Head First Java记录)

    本章讲解了对象的创建到被回收的过程,讲述了对象的生命周期   堆(heap)与栈(stack) 实例变量:实例变量是只声明在类下,方法外的变量(实例变量默认值为0/0.0/false,引用的默认值为n ...

  2. Java基础(十一) Stream I/O and Files

    Java基础(十一) Stream I/O and Files 1. 流的概念 程序的主要任务是操纵数据.在Java中,把一组有序的数据序列称为流. 依据操作的方向,能够把流分为输入流和输出流两种.程 ...

  3. Java基础十一--多态

    Java基础十一--多态 一.多态定义 简单说:就是一个对象对应着不同类型. 多态在代码中的体现: 父类或者接口的引用指向其子类的对象. /* 对象的多态性. class 动物 {} class 猫 ...

  4. java基础十[包、Jar存档文件和部署](阅读Head First Java记录)

    将Java的class文件生成为可执行的Java应用程序.Java应用程序有三种:完全在本机执行的Jar(例如本机的GUI可执行程序):完全在服务器端远程执行的(例如浏览器来进行存取):介于两者之间的 ...

  5. JAVA 基础开发环境 vscode 搭建 Windows下VSCode编译运行简单java

    JAVA 基础开发环境 vscode 搭建 来源 https://www.cnblogs.com/freewsf/p/7744728.html 对于使用 Visual Studio Code 的 Ja ...

  6. 003java面试笔记——【java基础篇】从团八百失败面试总结的java面试题(未完待续)

    8.java 线程     1)线程概念,线程与进程      线程:线程是“进程”中某个单一顺序的控制流.也被称为轻量进程.线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程.线 ...

  7. java基础IO流 复制键盘录入的目录,复制其中的.java文件到指定目录,指定目录中有重名,则改名 对加密文件计算字母个数

    package com.swift.jinji; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; im ...

  8. java基础(十一) 枚举类型

    枚举类型Enum的简介 1.什么是枚举类型 枚举类型: 就是由一组具有名的值的有限集合组成新的类型.(即新的类). 好像还是不懂,别急,咱们先来看一下 为什么要引入枚举类型 在没有引入枚举类型前,当我 ...

  9. java基础三 [深入多态,接口和多态](阅读Head First Java记录)

    抽象类和抽象方法 1.抽象类的声明方法,在前面加上抽象类的关键词abstract abstract class canine extends animal{      public void roam ...

随机推荐

  1. JavaScript 中的 Thunk 函数

    参数的求值策略: var x = 1; function f(m){ return m * 2; } f(x + 5); // x +5 在何时运算? 1.传值调用: var x = 1; funct ...

  2. VB6的函数指针传递

    Option Explicit Private Declare Function CallWindowProc Lib "user32" Alias "CallWindo ...

  3. Mysql分区简述

    1. 数据量大的时候 mysql分表非常常用,但是mysql还可以分区. 2. 分区就是把同一张表放在不同的磁盘文件上, 当查询的时候首先定位是哪个分区(查询的时候一定要用到分区的key) 3. 分区 ...

  4. Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法【转载】

    摘自:http://www.cnblogs.com/douqiumiao/default.aspx?opt=msg Validation failed for one or more entities ...

  5. CAD的API们

    AutoCAD有4种API,.net,lisp,activex和ObjectARX(C++).它们都是用来给cad写插件什么的,依赖cad运行. 另有一个RealDWG SDK,这是用来读写dwg或d ...

  6. POST内容太大的问题

    背景: 最近项目进入尾声,需要做交付测试,发现CMS生成页面在反复修改保存多次后,由于页面存在动态加载js的缘故,使得页面的内容越来越大,最终出现页面没有办法保存(ajax post将页面的内容发送给 ...

  7. 07 Linux su和sudo命令的区别

    一. 使用 su 命令临时切换用户身份 1.su 的适用条件和威力 su命令就是切换用户的工具,怎么理解呢?比如我们以普通用户beinan登录的,但要添加用户任务,执行useradd ,beinan用 ...

  8. 使用dojoConfig配置dojo(翻译)

    http://dojotoolkit.org/documentation/tutorials/1.10/dojo_config/index.html dojoConfig对象(原来是djConfig对 ...

  9. springboot教程

    http://www.cnblogs.com/java-zhao/tag/spring-boot/ http://blog.csdn.net/liaokailin/article/category/5 ...

  10. Array,ArrayList、List<T>、HashSet<T>、LinkedList<T>与Dictionary<K,V>

    Array: 数组在C#中最早出现的.在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单. 但是数组存在一些不足的地方.在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候 ...