RMI

来源:互联网 发布:亲亲吉祥网络 编辑:程序博客网 时间:2024/06/06 15:53

RMI

一、RMI简介

RMI——Remote Method Invocation,即远程方法调用。是Java的一组拥护开发分布式应用程序的API。。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

RMI主要用到了代理模式和序列化/反序列化。

二、RMI原理

一个RMI系统的组成元素:

1. 远程服务接口定义

2. 远程服务接口实现

3. 远程服务框架代理类(Skeleton

4. 客户端桩代理类(Stub)

5. 客户端

6. 一个RMI命名服务或注册中心,允许服务端注册服务,客户端发现服务

基本原理:


RMI系统的运行过程:

1. 生成一个远程接口

2. 实现远程接口(服务端程序)

3. 注册远程服务到注册中心

4. 启动服务端,等待客户端调用

5. 编写客户端程序

6. 客户端去注册中心获取服务

7. 客户端调用

8. 服务端相应,处理服务,返回相应

9. 客户端拿到响应,一次交互结束。

  时序图:


三、RMI实例

Server接口:

public interface MyRemote extends Remote {

    public String sayHello() throws RemoteException;

}

ServerImpl:服务端实现类:

public class MyRemoteImpl implements MyRemote, Serializable {

    public String sayHello() throws RemoteException {

        return "server say Hello!";

    }

    public static void main(String args[]) {

        MyRemote myRemote = new MyRemoteImpl();

        try {

            Registry registry = LocateRegistry.createRegistry(2001);  //开一个端口

            registry.rebind("RemoteHello", myRemote);     //服务端注册

            System.out.println("server is ready");

            try {

                Thread.sleep(1000 * 20); //由于是在一个工程内,同时runmain方法,这里sleep一下,保证客户端在20秒内调到

            } catch (InterruptedException e) {

                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

            }

        } catch (RemoteException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

    }

}

Client:客户端类

public class Client {

    public static void main(String args[]) {

        try {

            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 2001);  

            MyRemote myRemote = (MyRemote) registry.lookup("RemoteHello");   //从注册中心取到服务

            String s = myRemote.sayHello();//客户端请求服务

            System.out.println("s=" + s);

        } catch (NotBoundException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        } catch (RemoteException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

    }

}

四、RMI原理模拟

Server

package com.mylearn.rmi.principle.remote;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-30

 * Time: 下午5:21

 * CopyRight:360buy

 * Descrption:   声明接口,客户端和服务端都要知道

 * To change this template use File | Settings | File Templates.

 */

public interface Server {

    /**

     * 提供服务一:  sayHello

     *

     * @return

     */

    public String sayHello();

    /**

     * 提供服务二:  sayLove

     *

     * @return

     */

    public String sayLove();

}

ServerImpl

package com.mylearn.rmi.principle.remote;

import java.io.Serializable;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-30

 * Time: 下午5:24

 * CopyRight:360buy

 * Descrption: 服务端具体实现类,注意要实现Serilizable接口

 * To change this template use File | Settings | File Templates.

 */

public class ServerImpl implements Server, Serializable {

    public String sayHello() {

        return "server say hello!";  //To change body of implemented methods use File | Settings | File Templates.

    }

    public String sayLove() {

        return "server say love!";  //To change body of implemented methods use File | Settings | File Templates.

    }

}

Server_Skeleton :服务端代理类

package com.mylearn.rmi.principle.remote;

import javax.print.attribute.standard.Severity;

import java.io.*;

import java.net.ServerSocket;

import java.net.Socket;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-30

 * Time: 下午5:23

 * CopyRight:360buy

 * Descrption:  服务端代理类,代理类的作用就是实现类的封闭,

 * 1. 这里接收客户端的字节流,然后解析出客户端要请求的服务,

 * 2.然后找到服务的本尊,调用对应的方法,得出结果

 * 3. 然后把结果序列化,通过流的方式返回给客户端(其实也是客户端的代理对象)

 * To change this template use File | Settings | File Templates.

 */

public class Server_Skeleton implements Runnable {

    private Server server;   //声明代理对象

    public void run() {

        try {

            ServerSocket serverSocket = new ServerSocket(9090);    //开启socket服务端

            while (true) {

                Socket socket = serverSocket.accept(); //等待客户端请求

                System.out.println("服务端建立socket链接ok");

                InputStream inputStream = socket.getInputStream();

                OutputStream outputStream = socket.getOutputStream();

                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

                ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

                String method = (String) objectInputStream.readObject(); //获取客户端请求方法,反序列化

                if ("sayHello".equalsIgnoreCase(method)) {

                    //如果是saylHello方法,则调用ServerImpl去处理,代理模式

                    server = new ServerImpl();

                    String s = server.sayHello();

                    objectOutputStream.writeObject(s); //序列化

                    objectOutputStream.flush();

                }

                if ("sayLove".equalsIgnoreCase(method)) {

                    //如果是sayLove方法,则调用ServerImpl去处理

                    server = new ServerImpl();

                    String s = server.sayLove();

                    objectOutputStream.writeObject(s);

                    objectOutputStream.flush();

                }

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                }

                outputStream.close();

                inputStream.close(); //输入流不能提前关闭,否则报错

                socket.close();

                System.out.println("服务端响应结束");

            }

        } catch (IOException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        } catch (ClassNotFoundException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

    }

}

Client_Stub:客户端代理类

package com.mylearn.rmi.principle.local;

import com.mylearn.rmi.principle.remote.Server;

import java.io.*;

import java.net.Socket;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-30

 * Time: 下午5:24

 * CopyRight:360buy

 * Descrption: 客户端代理类

 * 1. 把客户端的请求通过流传给服务端(其实是服务端的代理类)

 * 2. 阻塞,等待服务端的返回,如果有响应,则读取响应信息,反序列化,展现结果

 * To change this template use File | Settings | File Templates.

 */

public class Client_Stub implements Server {

    private Socket socket;

    private void connect() {

        try {

            socket = new Socket("127.0.0.1", 9090);

        } catch (IOException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

    }

    public String sayHello() {

        return say("sayHello");

    }

    public String sayLove() {

        return say("sayLove");

    }

    public String say(String fieldName) {

        connect();//建立到服务端的链接

        try {

            InputStream inputStream = socket.getInputStream();

            OutputStream outputStream = socket.getOutputStream();

            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

            objectOutputStream.writeObject(fieldName);      //向服务端发送请求,序列化,请求调用服务端的sayHello方法

//            System.out.println("客户端发送请求,request sayHello接口");

            objectOutputStream.flush();

            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

            return (String) objectInputStream.readObject();    //阻塞,等待服务端发送消息,反序列化

        } catch (IOException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        } catch (ClassNotFoundException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

        return null;

    }

}

Client

package com.mylearn.rmi.principle.local;

import com.mylearn.rmi.principle.remote.Server_Skeleton;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-30

 * Time: 下午5:21

 * CopyRight:360buy

 * Descrption:  客户端对象

 * To change this template use File | Settings | File Templates.

 */

public class Client {

    public static void main(String args[]) {

        //1.开一个服务器线程

        final Thread threadServer1 = new Thread(new Server_Skeleton());

        //2.5个客户端线程请求sayHello

        for (int i = 0; i < 5; i++) {

            Thread threadClient1 = new Thread(new Runnable() {

                public void run() {

                    Client_Stub client_stub = new Client_Stub();

                    String response = client_stub.sayHello();

                    System.out.println("response1 = " + response);

                }

            });

            threadClient1.start();

        }

        //3.5个客户端线程请求sayLove

        for (int i = 0; i < 5; i++) {

            Thread threadClient2 = new Thread(new Runnable() {

                public void run() {

                    Client_Stub client_stub = new Client_Stub();

                    String response = client_stub.sayLove();

                    System.out.println("response2 = " + response);

                }

            });

            threadClient2.start();

        }

        threadServer1.start();//启动服务端代理类线程

        try {

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

    }

}

五、设计模式延伸

代理模式: 代理模式控制对象的访问。在代理类中会对客户端的访问做限制,达到某个条件才会调用对象本尊。如上文中的Server_Skeleton和Client_Stub对象都是代理类。ServerImpl是服务本尊。

装饰模式:装饰模式为对象增加行为。

适配器模式:代理和适配器都是会挡在其他对象的前面,并负责将请求转发给它们。适配器会改变对象适配的接口,而代理则实现相同的接口。

推荐: http://haolloyin.blog.51cto.com/1177454/332426

原创粉丝点击