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.
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 👇