纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

java RMI使用 详解Java 中 RMI 的使用

未读代码   2021-05-11 我要评论
想了解详解Java 中 RMI 的使用的相关内容吗未读代码在本文为您仔细讲解java RMI使用的相关知识和一些Code实例欢迎阅读和指正我们先划重点:java,RMI使用下面大家一起来学习吧。

RMI 介绍

RMI (Remote Method Invocation) 模型是一种分布式对象应用使用 RMI 技术可以使一个 JVM 中的对象调用另一个 JVM 中的对象方法并获取调用结果。这里的另一个 JVM 可以在同一台计算机也可以是远程计算机。因此RMI 意味着需要一个 Server 端和一个 Client 端。

Server 端通常会创建一个对象并使之可以被远程访问。

这个对象被称为远程对象。Server 端需要注册这个对象可以被 Client 远程访问。

Client 端调用可以被远程访问的对象上的方法Client 端就可以和 Server 端进行通信并相互传递信息。

说到这里是不是发现使用 RMI 在构建一个分布式应用时十分方便它和 RPC 一样可以实现分布式应用之间的互相通信甚至和现在的微服务思想都十分类似。

RMI 工作原理

正所谓 “知其然知其所以然”在开始编写 RMI 代码之前有必要了解一下 RMI 的工作原理RMI 中 Client 端是和 Server 端是如何通信的呢?

下图的可以帮助我们理解RMI 的工作流程。

从图中可以看到Client 端有一个被称 Stub 的东西有时也会被成为存根它是 RMI Client 的代理对象Stub 的主要功能是请求远程方法时构造一个信息块RMI 协议会把这个信息块发送给 Server 端。

这个信息块由几个部分组成:

  • 远程对象标识符。
  • 调用的方法描述。
  • 编组后的参数值(RMI协议中使用的是对象序列化)。

既然 Client 端有一个 Stub 可以构造信息块发送给 Server 端那么 Server 端必定会有一个接收这个信息快的对象称为 Skeleton 。

它主要的工作是:

  • 解析信息快中的调用对象标识符和方法描述在 Server 端调用具体的对象方法。
  • 取得调用的返回值或者异常值。
  • 把返回值进行编组返回给客户端 Stub.

到这里一次从 Client 端对 Server 端的调用结果就可以获取到了。

RMI 开发

通过上面的介绍知道了 RMI 的概念以及 RMI 的工作原理下面介绍 RMI 的开发流程。

这里会通过一个场景进行演示假设 Client 端需要查询用户信息而用户信息存在于 Server 端所以在 Server 端开放了 RMI 协议接口供客户端调用查询。

RMI Server

Server 端主要是构建一个可以被传输的类 User一个可以被远程访问的类 UserService同时这个对象要注册到 RMI 开放给客户端使用。

1.定义服务器接口(需要继承 Remote 类方法需要抛出 RemoteException)。

package com.wdbyte.rmi.server;

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


/**
 * RMI Server
 *
 * @author www.wdbyte.com
 * @date 2021/05/08
 */
public interface UserService extends Remote {

    /**
     * 查找用户
     * 
     * @param userId
     * @return
     * @throws RemoteException
     */
    User findUser(String userId) throws RemoteException;
}

User 对象在步骤 3 中定义。

2.实现服务器接口(需要继承 UnicastRemoteObject 类实现定义的接口)。

package com.wdbyte.rmi.server;

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

/**
 * @author www.wdbyte.com
 * @date 2021/05/08
 */
public class UserServiceImpl extends UnicastRemoteObject implements UserService {

    protected UserServiceImpl() throws RemoteException {
    }

    @Override
    public User findUser(String userId) throws RemoteException {
        // 加载在查询
         if ("00001".equals(userId)) {
            User user = new User();
            user.setName("金庸");
            user.setAge(100);
            user.setSkill("写作");
            return user;
        }
        throw new RemoteException("查无此人");
    }
}

3.定义传输的对象传输的对象需要实现序列化(Serializable)接口。

需要传输的类一定要实现序列化接口不然传输时会报错。IDEA 中如何生成 serialVersionUID在文章末尾也附上了简单教程。

package com.wdbyte.rmi.server;

import java.io.Serializable;

/**
 *
 * @author www.wdbyte.com
 * @date 2021/05/08
 */
public class User implements Serializable {

    private static final long serialVersionUID = 6490921832856589236L;

    private String name;
    private Integer age;
    private String skill;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
    
    @Override
    public String toString() {
        return "User{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", skill='" + skill + '\'' +
            '}';
    }
}

4.注册( rmiregistry)远程对象并启动服务端程序。

服务端绑定了 UserService 对象作为远程访问的对象启动时端口设置为 1900。

package com.wdbyte.rmi.server;

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

/**
 * RMI Server 端
 *
 * @author https://www.wdbyte.com
 * @date 2021/05/08
 */
public class RmiServer {

    public static void main(String[] args) {
        try {
            UserService userService = new UserServiceImpl();
            LocateRegistry.createRegistry(1900);
            Naming.rebind("rmi://localhost:1900/user", userService);
            System.out.println("start server,port is 1900");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

RMI Client

相比 Server 端Client 端就简单的多。直接引入可远程访问和需要传输的类通过端口和 Server 端绑定的地址就可以发起一次调用。

package com.wdbyte.rmi.client;

import java.rmi.Naming;

import com.wdbyte.rmi.server.User;
import com.wdbyte.rmi.server.UserService;

/**
 * @author https://www.wdbyte.com
 * @date 2021/05/08
 */
public class RmiClient {
    public static void main(String args[]) {
        User answer;
        String userId = "00001";
        try {
            // lookup method to find reference of remote object
            UserService access = (UserService)Naming.lookup("rmi://localhost:1900/user");
            answer = access.findUser(userId);
            System.out.println("query:" + userId);
            System.out.println("result:" + answer);
        } catch (Exception ae) {
            System.out.println(ae);
        }
    }
}

RMI 测试

启动 Server 端。

start server,port is 1900

启动 Client 端。

query:00001
result:User{name='金庸', age=100, skill='写作'}

如果 Client 端传入不存在的 userId。

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.RemoteException: 查无此人

serialVersionUID 的生成

IDEA 中生成 serialVersionUID打开设置如下图所示勾选。

选中要生成 serialVersionUID 的类按智能提示快捷键。

参考

[1] https://docs.oracle.com/javase/tutorial/rmi/overview.html


相关文章

猜您喜欢

  • jenkins打包发布vue项目 使用jenkins一键打包发布vue项目的实现

    想了解使用jenkins一键打包发布vue项目的实现的相关内容吗guojikun在本文为您仔细讲解jenkins打包发布vue项目的相关知识和一些Code实例欢迎阅读和指正我们先划重点:jenkins打包发布vue项目,jenkins打包发布vue下面大家一起来学习吧。..
  • Python逻辑回归 Python机器学习之逻辑回归

    想了解Python机器学习之逻辑回归的相关内容吗Flechazo_z在本文为您仔细讲解Python逻辑回归的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Python逻辑回归,Python机器学习下面大家一起来学习吧。..

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式