0
点赞
收藏
分享

微信扫一扫

自定义 RPC框架2——RMI实现RPC

雪域迷影 2022-04-16 阅读 49
rpcjava

RMI简介

**RMI(Remote Method Invocation)**远程方法调用

RMI是从JDK1.2推出的功能,它可以实现在一个JAVA应用中可以像调用本地方法一样调用另一个服务中Java应用(JVM)中的内容。

RMI是Java语言的远程调用,无法实现跨语言

执行流程

image-20220416103503619

**Registry(注册表)**是放置所有服务器对象的命名空间。每次服务端创建一个对象时,他都会使用bind()或者rebind()方法注册该对象。这些是使用称为绑定名称的唯一名称注册的。

要调用远程对象,客户端需要该对象的引用。即通过服务端绑定的名称从注册表中获取对象(lookup()方法)

API介绍

Remote

java.rmi.Remote

定义了此接口为远程调用接口。如果接口被外部调用,需要继承此接口。

public interface Remote{}

RemoteException

java.rmi.RemoteException

继承了Remote的接口中,如果方法是允许被远程调用的,需要抛出此异常。

UnicastRemoteObject

java.rmi.server.UnicastRemoteObject

此类实现了Remote接口和Serializable接口。

自定义接口实现类除了实现自定义接口还需要继承此类。

LocateRegisry

java.rmi.registry.LocateRegistry

可以通过LocateRegistry在本机上创建Registry,通过特定的端口就可以访问这个Registry

Naming

java.rmi.Naming

Naming定义了发布内可访问RMI名称。也是通过Naming获取到指定的远程方法。

代码实现

整体代码结构

image-20220416110113970

  • rmi_api是要被实现的接口层
  • rmi_client客户端,调用远程方法
  • rmi_server接口实现和注册接口到Registry

API接口层

代码结构

image-20220416110810607

接口FirstInterface

package com.shen.rmi.api;

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

//定义一个远程服务接口,rmi强制要求,必须是remote接口的实现
public interface FirstInterface extends Remote {
    //rmi强制要求,所有的远程服务方法,必须抛出RemoteException
    String first(String name) throws RemoteException;
}

rmi_server服务端

代码结构

image-20220416111953079

使用9999端口完成注册

FirstRMIImpl接口实现类

package com.shen.rmi.impl;

import com.shen.rmi.api.FirstInterface;

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

//实现远程服务接口,所有的远程服务实现,必须是remote接口的直接或间接实现类
//如果不会创建rmi的服务标准实现,可以继承UnicaastRemoteObject
//rmi强制要求,所有方法必须抛出RemoteException,包括构造方法
public class FirstRMIImpl extends UnicastRemoteObject implements FirstInterface, Remote {
    public FirstRMIImpl() throws RemoteException {
    }

    @Override
    public String first(String name) throws RemoteException {
        System.out.println("客户端请求参数是:" + name);
        return "你好,"+name;
    }
}

MainClass启动类

负责将服务注册到registry(注册中心)上

package com.shen.rmi;

import com.shen.rmi.api.FirstInterface;
import com.shen.rmi.impl.FirstRMIImpl;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

//主方法,创建一个服务实现对象,提供服务,并注册到Registry上
//RMI的Registry在创建的时候,会直接启动一个子线程,并升级为守护线程(服务线程,精灵线程),提供持久的服务
public class MainClass {
    public static void main(String[] args) {
        try {
            System.out.println("服务器启动中。。。");
            //创建服务对象
            FirstInterface firstInterface = new FirstRMIImpl();
            //注册到Registry(注册中心)上
            LocateRegistry.createRegistry(9999);
            //绑定一个服务到注册中心,提供命名,格式为:rmi://ip:port/别名
            //如果服务重复,抛出异常。重复的定义是命名冲突
            //Naming.bind("rmi://localhost:9999/first",firstInterface);
            //重新绑定一个服务到注册中心,和bind区别,命名冲突直接覆盖,没有则新增
            Naming.rebind("rmi://localhost:9999/first",firstInterface);

            System.out.println("服务器启动完毕!");
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

pom依赖导入

<dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>rmi_api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

rmi_client客户端

项目结构

image-20220416120456974

ClientMainClass启动类

package com.shen.rmi;

import com.shen.rmi.api.FirstInterface;

import java.rmi.Naming;

//客户端主方法
public class ClientMainClass {
    public static void main(String[] args) {
        // 代理对象的创建
        FirstInterface firstInterface = null;
        try {
            //使用lookup找服务,通过名字找服务,并自动创建代理对象
            //类型是Object,对象一定是Proxy的子类型,且一定实现了服务接口
            firstInterface = (FirstInterface) Naming.lookup("rmi://localhost:9999/first");
            System.out.println("对象的类型是:" + firstInterface.getClass().getName());
            System.out.println(firstInterface.first("嘿嘿嘿"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

pom依赖导入

<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>rmi_api</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

项目启动

需要先启动rmi_server下的MainClass启动类

再启动rmi_client下的ClientMainClass

源码地址

https://gitee.com/shen1shen1/new_rpc

举报

相关推荐

0 条评论