Java之RMI(远程方法调用)

RMI(Remote Method Invocation)中文名称是远程方法调用,可用于分布式计算。
这里就不去详细介绍RMI了,本Blog主要讲叙RMI实战和有哪些需要注意的地方,如果想要查看详细介绍请查看:百度百科RMI

RMI分为服务端和客户端

服务端:

创建服务端:

LocateRegistry.createRegistry(端口);
Naming.rebind("rmi://IP地址:端口/RMI服务名称",RMI服务对象);//rebind也可以用bind替代

示例:

LocateRegistry.createRegistry(10010);
Naming.rebind("rmi://127.0.0.1:10010/Test", new TestServer());

RMI服务对象的类定义规则:

1.必须继承UnicastRemoteObject

2.构造方法必须声明抛出RemoteException

3.必须实现自定义的业务接口,不能直接实现Remote,必须将客户端要调用的接口抽取到接口中去

4.客户端要调用的接口方法返回值必须实现Serializable,虽然发布RMI服务时不会报错但RMI客户端调用此方法时会报错

RMI服务对象的接口定义规则:

1.接口必须继承Remote

2.接口方法必须声明抛出RemoteException

示例:

public interface TestServerInterface extends Remote {
    String getString() throws RemoteException;
    Student getStudent(String name) throws RemoteException;
}
public class TestServer extends UnicastRemoteObject implements TestServerInterface {
    public TestServer() throws RemoteException {
        super();
    }
    @Override
    public String getString() throws RemoteException {
        return System.currentTimeMillis()+":有客户端调用了此方法";
    }
    @Override
    public Student getStudent(String name) throws RemoteException {
        return new Student(name+System.currentTimeMillis());
    }
}

客户端:

创建并使用客户端:

RMI服务对象的接口 server= (RMI服务对象的接口) Naming.lookup("rmi://IP地址:端口/RMI服务名称");
返回值 result=server.你要调用的方法(可能需要传入的参数);

示例:

TestServerInterface serverInterface= (TestServerInterface) Naming.lookup("rmi://localhost:10010/Test");
System.out.println(">>>" + serverInterface.getString());
System.out.println(">>>" + serverInterface.getStudent("name1"));

RMI服务对象的接口定义规则:

1.可以和服务端定义的接口方法不一致,服务端有的这边可以没有,服务端没有的这边可以有,但调用时会报错
2.无须继承Remote,继承也行不过没意义
3.接口方法无须声明抛出RemoteException,声明抛出也行不过没意义
4.一般来说和服务端保持一致即可
示例:

public interface TestServerInterface {
    String getString();
    Student getStudent();
}

特别说明:

一、客户端使用的”RMI服务对象的接口”和服务端用”RMI服务对象的接口”是两个不用的类,因为客户端和服务端一般不在一台机器上。

二、如果客户端返回的值是自定义类型,客户端所定义接收的返回值则有下规则:

1.必须实现Serializable

2.如果服务端没有定义serialVersionUID,客户端这边也必须没有定义serialVersionUID

3.如果服务端有定义serialVersionUID,客户端这边也必须定义serialVersionUID并且serialVersionUID值要和服务端serialVersionUID值一致,否则会报未序列化和版本号不一致异常

示例1:

服务端返回自定义类型:
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public String toString(){
        return name;
    }
}
客户端接受自定义类型:
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public String toString(){
        return name;
    }
}

示例2:

服务端返回自定义类型:
public class Student implements Serializable {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public String toString(){
        return name;
    }
}
客户端接受自定义类型:
public class Student implements Serializable {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public String toString(){
        return name;
    }
}

完整代码:

项目图:
项目图

服务端:

package test;

import java.io.Serializable;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

public class RmiServerMain {
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(10010);
        Naming.bind("rmi://127.0.0.1:10010/Test", new TestServer());
    }
}

interface TestServerInterface extends Remote {

    String getString() throws RemoteException;

    Student getStudent(String name) throws RemoteException;
}

class TestServer extends UnicastRemoteObject implements TestServerInterface {

    private static final long serialVersionUID = 1L;

    public TestServer() throws RemoteException {
        super();
    }

    @Override
    public String getString() throws RemoteException {
        return System.currentTimeMillis() + ":有客户端调用了此方法";
    }

    @Override
    public Student getStudent(String name) throws RemoteException {
        return new Student(name + System.currentTimeMillis());
    }
}

class Student implements Serializable {

    private static final long serialVersionUID = 110L;

    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String toString() {
        return getClass().getSimpleName() + ":name=" + name;
    }
}

客户端

package test;

import java.io.Serializable;
import java.rmi.Naming;

public class RmiClientMain {
    public static void main(String[] args) throws Exception {
        TestServerInterface serverInterface = (TestServerInterface) Naming.lookup("rmi://127.0.0.1:10010/Test");
        System.out.println(">>>" + serverInterface.getString());
        System.out.println(">>>" + serverInterface.getStudent("StuName"));
    }
}

/** * 客户端的服务接口,不是必须继承Remote,并且方法不是必须申明抛出RemoteException<br> * 但包名、类名必须要和服务端完全一致。<br> * 方法可以删掉、可以乱加,但乱加的方法你只要不调用就行,以调用就报错。<br> * 方法的结构不同改,如返回类型,参数类型。 * * @author Tang * */
interface TestServerInterface {

    String getString();

    Student getStudent(String name);
}

class Student implements Serializable {

    /** * serialVersionUID变量必须和服务端保持一致。<br> * 如果服务端没有定义此变量,客户端这里也必须不要定义此变量<br> * 如果服务端有定义此变量,客户端这里也必须要定义此变量,并且变量的值也要相同 */
    private static final long serialVersionUID = 110L;

    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String toString() {
        return getClass().getSimpleName() + ":name=" + name;
    }
}

转载于:https://my.oschina.net/tangzhichao/blog/781429

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值