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

本文介绍了Java RMI(Remote Method Invocation)的概念、执行流程,包括Registry的作用,API接口的实现,以及如何在服务端启动、注册接口和客户端调用。展示了从接口定义、服务器端实现到客户端连接的完整步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值