I wrote an implementation case of Java RMI (remote method call)

I simply wrote an implementation case of Java RMI (remote method call).

In order to better understand RMI (remote method call), the meaning of serialization and so on, it took more than three days to build an implementation case of Java RMI.

!!! High energy warning!!!

The amount of code is a little large. A diagram is attached for understanding

The whole process is divided into two major steps

  • Step 1 - registration process: the client obtains the remote client object specified by the registration center through the specified route;
  • Part II - service invocation process: the client accesses the remote server (proxy service) through the remote client object, so as to access the implementation of the real service

Adjust your posture for comfort... Look at the nonsense!!!

1. Define remote tag interface

Interface oriented programming, the specific role depends on how to use the following code

//Tag interface: directly or indirectly implementing MyRMI interface will obtain the ability of remote call
public interface MyRMI{
}

2. Prepare RMI service registry

Registry class: used to register and obtain services. The core is the hashMap routing table object

/**
 * Registry: maintains the registry of service publications
 */
public class MyRMIRegistry {
    //Default port
    public final int REGISTRY_PORT = 10099;
    private String host;
    private int port;
    private Map<String, MyRMI> bindings;

    public MyRMIRegistry(int port){
        this.port = port;
    }
    public MyRMIRegistry(String host, int port){
        this.host=host;
        this.port=port;
    }

    public void createRegistry(String serverName,MyRMI myRMI){
        //Register the service and start the service
        this.bindings = new HashMap<>();
        String host = null;
        try {
            host = Inet4Address.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //Routing rules can be defined by themselves as long as the Key is unique
        String binding = "myrmi://"+host+":"+port+"/"+serverName;
        this.bindings.put("myrmi://"+host+":"+port+"/"+serverName,myRMI);
        System.out.println("Registered services include:"+bindings.keySet().toString());
        MyRMIRegistryServer myRMIRegistryServer = new MyRMIRegistryServer(this.port, this.bindings);
        Executors.newCachedThreadPool().submit(myRMIRegistryServer); //Thread pool startup service

    }

    public MyRMI getRegistry(String serverName){
        Socket socket = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        MyRMI myRMI = null;
        //Pass
        try {
            socket = new Socket(host, port);
            out = new ObjectOutputStream(socket.getOutputStream());
            out.writeObject("myrmi://"+host+":"+port+"/"+serverName);
            in = new ObjectInputStream(socket.getInputStream());
            myRMI = (MyRMI)in.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return myRMI;
    }
}

RMI registry service obtaining thread: start the registry service and wait for the client to obtain the remote client in the routing table

/**
 * RMI Registry get service thread
 */
public class MyRMIRegistryServer implements Runnable {
    private int port;
    private Map<String, MyRMI> bindings;
    public MyRMIRegistryServer(Integer port,Map<String, MyRMI> bindings){
        this.port = port;
        this.bindings = bindings;
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            serverSocket = new ServerSocket(this.port);
            while(true){
                Socket socket = serverSocket.accept();
                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());
                //See what services the client wants
                String serverName = (String)in.readObject();
                Iterator iterator = bindings.keySet().iterator();
                while (iterator.hasNext()){
                    String key = (String) iterator.next();
                    if(serverName.equals(key)){
                        //Response service object to client
                        MyRMI myRMI = bindings.get(key);
                        out.writeObject(myRMI);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            //Enter after exception
            try {
                if (out!=null)  out.close();
                if (in!=null)   in.close();
                if (serverSocket!=null) serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

3. Define the service interface to be published

The interface that needs to provide RMI service must inherit the custom MyRMI tag interface

/**
 * Service interface
 */
public interface Hello extends MyRMI {
    public String sayHello(String name);
}

4. Entity classes used by services

/**
 * Object data class: Person
 */
public class Person implements Serializable {
    //Serialized version UID
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    private String sex;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + ", age=" + age + ", sex='" + sex + '}';
    }
    public Person() {
    }
    public Person(String name, Integer age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}

5. Implement the service interface to be published

/**
 * Service realization provided externally
 */
public class HelloImpl implements Hello {
    private static File file = new File("D:/HelloRMI.txt");
    private static List<Person> list = new ArrayList<>();

    @Override
    public String sayHello(String name) {
        String result = "Not obtained"+name+"Information";
        try {
            List<Person> personList = readList();
            for(Person person:personList){
                if (person.getName().equals(name)){
                    result = "Hello , welcome to the RMI! "
                            + "full name:"+name + " Age:"+person.getAge()+" Gender:"+person.getSex();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return result;
    }


    /**
     * Generate data to prepare for testing
     * @param args
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Data preparation: all collection classes implement the Serializable interface
        list.add(new Person("Zhang San", 38, "male"));
        list.add(new Person("Li Si", 38, "male"));
        list.add(new Person("Like flowers", 18, "female"));
        //Persistent object data
        writerList(list);
        //Query persistent object data
        List<Person> personList = readList();
        System.out.println("Traversing persistent object data>");
        for (Person person : personList) {
            System.out.println(person);
            if (person.getAge() == 38) {
                person.setAge(18);
            }
        }

    }

    public static void writerList(List<Person> list) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        objectOutputStream.writeObject(list);
        objectOutputStream.close();
    }

    public static List<Person> readList() throws IOException, ClassNotFoundException {
        //Read normal file deserialization
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        List<Person> personList = (List<Person>) objectInputStream.readObject();
        objectInputStream.close();
        return personList;
    }
}

6. Thread class of remote client

Remote client class for automatically generating service interface (inheriting MyRMI tag interface): this class was originally implemented as a general class. In order to facilitate implementation, it directly implements the Hello interface

/**
 * Generation of thread class of remote client:
 *      In order to facilitate the implementation, the service interface is written directly here
 */
public class HelloClientThread implements Hello,Serializable {
    //Serialized version UID
    private static final long serialVersionUID = 1L;
    private Map<String,Object> map = new HashMap<>(); //Message object: method name and parameter object
    private String ip;
    private int port;

    public HelloClientThread(String ip, int port){
        this.ip = ip;
        this.port = port;
    }

    @Override
    public String sayHello(String name) {
        map.put("sayHello",name);
        String result = (String)send();
        return result;
    }

    private Object send(){
        Object o =null;
        Socket socket = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            socket = new Socket(ip, port);
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());
            //Tell the server what service I want to call
            out.writeObject(map);
            //Get service implementation object
            o = in.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if (out!=null)  out.close();
                if (in!=null)   in.close();
                if (socket!=null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return o;
    }
}

7. Thread class of remote server

Remote server class for automatic generation of service interface (inheriting MyRMI tag interface): this class was originally implemented as a general class. In order to facilitate implementation, some codes have not been decoupled and general

/**
 * Generation of thread class on remote server:
 *      To facilitate implementation, the service thread class is directly implemented here
 */
public class HelloServerThread implements Runnable {
    private Integer port;
    private MyRMI myRMI;
    public HelloServerThread(Integer port, MyRMI myRMI){
        this.port = port;
        this.myRMI = myRMI;
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            serverSocket = new ServerSocket(this.port);
            while(true){
                Socket socket = serverSocket.accept();
                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());
                //See what services the client wants
                Map map = (Map)in.readObject();
                Iterator iterator = map.keySet().iterator();
                while (iterator.hasNext()){
                    String key = (String) iterator.next();
                    if("sayHello".equals(key)){
                        //Response service object to client
                        Hello hello = (Hello)myRMI;
                        String result = hello.sayHello((String) map.get(key));
                        out.writeObject(result);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            //Enter after exception
            try {
                if (out!=null)  out.close();
                if (in!=null)   in.close();
                if (serverSocket!=null) serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
    
}

8. Classes generated and started by remote client and remote server

/**
 * Classes generated and started by remote client and remote server
 */
public class RemoteSocketObject{
    //Default port
    private int port=18999;

    //Specify the remote communication port and proxy service
    public MyRMI createRemoteClient(MyRMI myRMI,int port){
        if (port > 0)
            this.port=port;

        MyRMI myRMIClient = null;
        try {
            //Generate the underlying communication server and start it
            HelloServerThread helloServerThread = new HelloServerThread(this.port, myRMI);
            Executors.newCachedThreadPool().submit(helloServerThread); //Thread pool startup service
            //Generate bottom communication client
            String localHost = Inet4Address.getLocalHost().getHostAddress();
            System.out.println("host="+localHost+",port="+this.port);
            myRMIClient= new HelloClientThread(localHost, this.port);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return myRMIClient;
    }
    
}

9. Service release

/**
 * RMI Service publishing class
 */
public class HelloServer {
    public static void main(String[] args) {

        System.out.println("Create Hello Remote Method Invocation...");
        //Instantiate a Hello
        Hello hello = new HelloImpl();
        //Convert to remote service and provide remote client
        Hello remoteClient = (Hello)new RemoteSocketObject().createRemoteClient(hello, 0);
        //Hosting the service implementation to the Socket service
        MyRMIRegistry myRMIRegistry = new MyRMIRegistry(16000);
        //Start thread service
        myRMIRegistry.createRegistry("Hello",remoteClient);

    }
}

10. Client test class

/**
 * Client test class
 *      The client only knows the service interface, the address of the service publication and the name of the service publication
 */
public class TestHello {
    public static void main(String[] args) {
        //Note that it's not 127.0.0.1. I don't know the host. Look at the information printed after the server is started
        //Port 16000 is the port of the registry. The port of the underlying proxy service does not need to be known by the client
        MyRMIRegistry client = new MyRMIRegistry("192.168.233.1", 16000);
        Hello hello = (Hello) client.getRegistry("Hello");
        System.out.println(hello.sayHello("Zhang San"));
    }
}

11. Summary

The whole code, in the real scene:

The client only knows: TestHello class, Hello interface definition, MyRMI tag interface, MyRMIRegistry registration class code (only the Key is known in the routing table, and the specific value is not known);

The server only knows: Hello interface, HelloImpl service implementation class, MyRMI tag interface, MyRMIRegistry registration class code (Key and specific value are known in the routing table);

Other code implementations are insensitive. In order to simply implement the remote client and remote server, the service interface is coupled to them, which is not decoupled and universal.

Previous articles on Java

Java full stack learning route, learning resources and interview questions

What is a good architect in my heart?

Download classic programming books for free

More quality articles and resources 👇

Original is not easy, triple support: share, like, watching 👇

Keywords: Java

Added by eruna on Sat, 05 Mar 2022 18:35:57 +0200