java RMI详解

1. 什么是RMI

rmi 就是Java的远程方法调用 类似于rpc 只不过rpc是与语言无关的,rmi可以理解为是Java版本的rpc

2. 举例说明一下rmi

我们在机器1中 写一个接口 接口的实现作用就是返回一个字符串

package com.study.RMIServer;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MouthInterface extends Remote  {
    public String say() throws RemoteException;
}

可以看见要想可以被远程调用 必须要实现Remote接口,并且接口中的方法必须抛出异常

接下来我们写出这个接口的实现

package com.study.RMIServer;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class MouthImpl extends UnicastRemoteObject implements MouthInterface{

    public MouthImpl() throws RemoteException{
        super();
    }
    @Override
    public String say() throws RemoteException {
        return "你成功引起了我的注意";
    }
}

接口的实现必须继承unicastRemoteObject接口
然后在实现类中的构造函数抛出异常

至此我们的实现类就就写完了

接下来就是最后一步,启动我们的服务然后等待其他机器的调用

package com.study.RMIServer;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Locale;

public class ServerStart {
    public static void main(String[] args) {
        try {
            //开启注册中心 创建互联的端口号
            LocateRegistry.createRegistry(1099);
            //实例化服务
            MouthInterface china = new MouthImpl();
            //注册服务名
            Naming.rebind("server1",china)
            System.out.println("服务已启动");
        } catch (RemoteException e) {
            e.printStackTrace();
            System.out.println("RemoteExcetion");
        }catch (Exception w){
            System.out.println("服务异常");
        }
    }
}

至此我们的服务端已经编写完成了
回头看一下我们的整个步骤

  1. 编写接口继承Remote 方法中要抛出异常 这个类最终要打成jar包,给我们的客户端调用用,注意打包的是接口不是实现
  2. 编写接口的实现类,继承unicastRemoteObject类 并且在构造函数中抛出异常
  3. 编写服务启动程序 也叫做骨架 skeleton 其实就是一个网络编程,通过LocateRegistry.create(1099);来注册我们监听的端口,只有我们的客户端通过网络向我们监听的端口发送消息 就会被服务端处理 稍后我会写一个demo来让大家简单的理解一下内部的实现机制

然后客户端就简单了我们首先要把之前接口打成的jar包引入我们的客户端工程 客户端在另一台机器2中 (也可以在同一个机器中编写)

客户端代码如下

import java.net.MalformedURLException;
//java提供的jar
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class RMIClient {
    public static void main(String[] args) {
        try {
            MouthInterface mouth = (MouthInterface)Naming.lookup("//10.13.94.10:1099/server1");
            System.out.println(mouth.say());
        } catch (NotBoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}


其中LocateRegist.create()与Naming.rebind()的作用
主要就是两个一个是确定我们服务监听的端口号
一个是命名服务
在调用端中
naming.looking("//ip:port/服务名")
通过服务名找到对应得服务端实现 也就是说调用方通过网络发送服务名
服务方通过服务名就知道要调用的是接口的哪个实现
Naming.lookup("//10.13.94.10:1099/server1")
这个其实是Java内部实现的 隐藏了细节 客户端的网络模块,叫stub 也叫桩 稍后会在另一文章中介绍一下桩和骨架的基本原理

Naming.rebind(); 这个方法其实就是一个命名服务 客户端通过服务名发送给服务端 服务端根据这个名字就能知道调用的是哪个实现从而返回相应的结果

3.RMi与RPC的区别

  1. rmi只能由于java rpc是一个协议,可以有不同的实现
  2. rmi的返回值可以是java的类型 对象 rpc统一返回一种格式需要解析
  3. 调用方式不同 rmi有一个命名服务 在服务端会对各个实例进行命名,然后客户端通过ip:端口/服务名 的方式调用

4.rmi的缺点

  1. 客户端调用与ip 端口绑定的太死 虽然可以脱离在代码之外
  2. 客户端与服务端必须是java语言编写的

你可能感兴趣的:(Java,RMI)