[编织消息框架][消息服务]rmi

 RMI(即Remote Method Invoke 远程方法调用)

  • 远程对象: 用于远程客户端调用 必需继承java.rmi.Remote,每个调用方法必须添加java.rmi.RemoteException异常

  • 远程对象实现:用于远程服务器,实现调用逻辑 必需继承UnicastRemoteObject

  • 远程服务器:通过LocateRegistry注册服务

  • 远程客户端:通过LocateRegistry查找服务,调用方法即可发送内容 Naming是LocateRegistry的辅助工具类

 

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

public interface ITestRMIService extends Remote {
    //必须加RemoteException否则运行出错: java.rmi.server.ExportException
    public String a(String content) throws RemoteException;
    
    public TestRMIObj b(TestRMIObj input) throws RemoteException;
}
// UnicastRemoteObject用于导出的远程对象和获得与该远程对象通信的存根。否则运行出错:java.rmi.MarshalException
public class TestRMIServiceImpl extends UnicastRemoteObject implements ITestRMIService {
    private static final long serialVersionUID = -6460154344452562895L;

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

    @Override
    public String a(String content) {
        System.out.println("call : a"+ content );
        return "server >> " + content;
    }

    @Override
    public TestRMIObj b(TestRMIObj input) throws RemoteException {
        System.out.println("call b : "+ input.getB().length );
        input.setA(12);
        return input;
    }
}
//必须实现Serializable该对象要支持 Serializable
public class TestRMIObj implements Serializable {

    private static final long serialVersionUID = 2367853017282270281L;
    private int a;
    private Integer[] b;

    public int getA() {
        return a;
    }

    public Integer[] getB() {
        return b;
    }

    public void setA(int a) {
        this.a = a;
    }

    public static TestRMIObj of(int a, Integer... b) {
        TestRMIObj ret = new TestRMIObj();
        ret.a = a;
        ret.b = b;
        return ret;
    }
}
public class ServerRMI {
    public static void main(String[] args) {
        try {
            // 实例化实现了IService接口的远程服务ServiceImpl对象
            ITestRMIService service02 = new TestRMIServiceImpl();
            // 本地主机上的远程对象注册表Registry的实例,并指定端口为8888
            LocateRegistry.createRegistry(8888);
            // 把远程对象注册到RMI注册服务器上,并命名为service02
            // 绑定的URL标准格式为:rmi://host:port/name
            Naming.bind("rmi://localhost:8888/service02", service02);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("服务器向命名表注册了1个远程服务对象!");
    }
}
public class ClientRMI {
    private ITestRMIService service;

    public void start() {
        String url = "rmi://localhost:8888/";
        try {
            // 在RMI服务注册表中查找名称为service02的对象,并调用其上的方法
            service = (ITestRMIService) Naming.lookup(url + "service02");
            System.out.println(service.a("你好!"));
            System.out.println(service.b(TestRMIObj.of(1, 2, 3, 4)).getA());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        ClientRMI rmi = new ClientRMI();
        rmi.start();
        while (true) {
            Thread.sleep(500);
            rmi.service.a("a");
        }
    }
}

 

使用rmi开发网络通信非常简单,代码量比写model还少,开发者不需要考虑对象序列化,网络IO模型,粘包/半包、传输协议等问题

但它应用场景非常少,不适合大规模的应用,比较适合s/s服务间调用,原因是对象序列化数据量大,采用的是BIO模型

RMI与RPC有什么区别呢

RPC(Remote Procedure Call Protocol)远程过程调用协议

程序可使用这种协议向网络中的另一台计算机上的程序请求服务。由于使用 RPC 的程序不必了解支持通信的网络协议的情况,因此 RPC 提高了程序的互操作性。在 RPC 中,发出请求的程序是客户程序,而提供服务的程序是服务器

可以这样理解rmi是sun公司基于rpc制定的实现标准

posted @ 2017-04-19 18:29  solq321  阅读(226)  评论(0编辑  收藏  举报