java Foundation Consolidation - the first AiYWM in the universe: in order to make a living, handwritten RPC04~Version04 (how can an object be equivalent to a pile of member variables) are set up

Version04:
In version 03, if there are some other methods in my interface, do you have to pass an int type every time, such as 221? Can each method only receive integers? Can't other types? So I have to go further and shield this difference. Just like min Xiaoyan didn't want to see the details of processing the network at the beginning, how do we do it? Isn't it shielding some details

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package entity;

import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * The client minxiaoyan and the server Xiaohu are known entities. The client needs to get the pojo object data, and the server needs to operate the object. In our situation, the server needs to query the object according to the information provided by the client, and then return the found object to the client
 * 
 * For example, if another class on the local machine wants to use my pillow object and give it to him, this is not local communication or transmission. However, if a thing on another machine wants to use my pillow object and give it to him, this is not remote communication
 * @author HuHongBo
 * @version 2022 May 5
 */
//@Builder
//@Data
//@NoArgsConstructor
//@AllArgsConstructor
public class Pilliow implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String clothesColor;

	public Pilliow(Integer id, String clothesColor) {
		super();
		this.id = id;
		this.clothesColor = clothesColor;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getClothesColor() {
		return clothesColor;
	}

	public void setClothesColor(String clothesColor) {
		this.clothesColor = clothesColor;
	}

	@Override
	public String toString() {
		return "Pilliow [id=" + id + ", clothesColor=" + clothesColor + "]";
	}

}

Then, when Xiao Hu gave his id to min Xiaoyan, he began to wait:
When will you send pilot?
When will you send pilot? When will you send pilot?
When will you send pilot? When will you send pilot? When will you send pilot?
...
Then min Xiaoyan, as the server, calls the service (method) to find the pilot with id and starts sending the pilot to Xiao Hu.
After Xiao Hu received the pilot, he stuffed the pilot into the cabinet and waited for the customer to pick it up.
There are some lazy details. See the notes:

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package client;

import entity.Pilliow;
import server.PilliowService;
import server.Stub;

/**
 * The client needs to write the ID value of id=221 to the server, so that the server can help us find the pilot according to this ID
 * 	Since only binary can be transmitted on the network, we have to convert this id value, that is, 221, into binary
 * 	Java You can use these three sentences in the code, which will automatically help us convert the 221 value of id into the binary corresponding to 221
 * 		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
		dataOutputStream.writeInt(221);
 * 
 * @author HuHongBo
 * @version 2022 May 12
 */
public class Client {
	public static void main(String[] args) throws Exception {
//		Stub stub = new Stub();
//		System.out.println(stub.getPilliowByPilliowId(221));
		/**
		 * I'll upgrade my client now. I just want you to provide or return a server (that is, our server interface) to me,
		 * Then we can call the method of the server for remote access (it's equivalent to realizing remote access, because I can already get the service of your server
		 * (That is, the getPilliowByPilliowId method,)) receives the id passed by the client, finds the corresponding Pilliow quickly, and then passes it quickly
		 * To the client, I'm done)
		 * 
		 * 
		 * In a word, it's stub Getstub () returns the dynamically generated object to us, and the class to which this object belongs is a class that implements the PilliowService interface of the server
		 */
		PilliowService pilliowService = Stub.getStub();
		/**
		 * pilliowService.getPilliowByPilliowId(221),Although this is a simple method call, it is to remotely access getPilliowByPilliowId elsewhere through the network
		 * ´╝îIf you think about it, the id is someone else's client. This method is someone else's server-side. This is not remote access. What is it?
		 * So, that is to say, when we call the getpilliowbypid method, this method also adds some code to deal with the details of the network, so that we can call the server-side method remotely or call it remotely
		 * 
		 * pilliowService It is the proxy class generated dynamically through dynamic proxy. When pilliowService calls the getPilliowByPilliowId method, this call will be processed by the invoking processor InvocationHandler of the dynamic agent
		 * How to deal with it is the code we implement in the invoke method
		 * 
		 * What code is added to deal with the details of the network? - > dynamic agent in agent mode
		 * 		If I have a Class A that implements the PilliowService interface, there must be a (Abstract) method in my class a that implements or rewrites the so-called service end in this interface
		 * 				In this rewritten method, I added all kinds of code to deal with network details. Then I can directly call the so-called server-side method in class A to realize "remote access server"
		 * 			Now the question arises: does my class A write it by hand, or does it hand over the control or the creation right of the class like spring?
		 * 				If there is a new interface (the new so-called server-side method in), do I have to rewrite class A and class AAA again It must be inconvenient
		 * 				So we imitate spring and let others help us create this class A dynamically (that is, let this class A be generated dynamically). To dynamically generate A new class, you need A dynamic proxy
		 */
		System.out.println(pilliowService.getPilliowByPilliowId(221));
		
	}
}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;

import entity.Pilliow;

/**
 * Define the service interface that the client needs to call and the server needs to provide
 * getUserByUserId()This method or the class of this method is one of our services for others to call
		 * 
		 * The idea of calling the service is: I want to check the person with ID 221. Does my client have to write the id=221 to the server first
		 * Then, after the server finds this person, it turns it into binary and gives it to me, and the client returns it (writes it back)
		 * I'll analyze it after I receive it
 * @author HuHongBo
 * @version 2022 May 5
 */
public interface PilliowService {
	/**
	 * The client calls the implementation class of the server through this interface
	 * @param id
	 * @return
	 * @author HuHongBo
	 */
    Pilliow getPilliowByPilliowId(Integer id);
}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;
import entity.Pilliow;

/**
 * getPilliowByPilliowId()This method or the class of this method is one of our services for others to call
		 * 
		 * The idea of calling the service is: I want to check the person with ID 221. Does my client have to write the id=221 to the server first
		 * Then, after the server finds this person, it turns it into binary and gives it to me, and the client returns it (writes it back)
		 * I'll analyze it after I receive it
 * @author HuHongBo
 * @version 2022 May 5
 */
public class PilliowServiceImpl implements PilliowService{

	@Override
	public Pilliow getPilliowByPilliowId(Integer id) {
		/**
		 * Of course, the values of these member variables in the entity class are generally found from the database or cache
		 */
		return new Pilliow(id, "black Sweater");
	}

}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import entity.Pilliow;


/**
 * 
 * getPilliowByPilliowId()This method or the class of this method is one of our services for others to call
* 
* The idea of calling the service is: I want to check the person with ID 221. Does my client have to write the id=221 to the server first
* Then, after the server finds this person, it turns it into binary and gives it to me, and the client returns it (writes it back)
* I'll analyze it after I receive it
 * 
 * @author HuHongBo
 * @version 2022 May 12
 */
public class Server {
	private static boolean flag = true;
	
	public static void main(String[] args) throws Exception{
		/**
		 * Others can remotely connect to my Server, that is, service, through this port
		 */
		ServerSocket serverSocket = new ServerSocket(2221);
		while(flag){
			/**
			 * Receive a client connection through accept
			 */
			Socket socket = serverSocket.accept();
			/**
			 * Handle the connection of the client
			 */
			process(socket);
			socket.close();
		}
	}

	/**
	 * 
	 * @param socket
	 * @throws Exception
	 * @author HuHongBo
	 */
	private static void process(Socket socket) throws Exception {
		/**
		 * Get the input stream
		 */
		InputStream inputStream = socket.getInputStream();
		OutputStream outputStream = socket.getOutputStream();
		ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
		DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
		
		String methodName = objectInputStream.readUTF();
		Class[] parameterTypes = (Class[])objectInputStream.readObject();
		Object[] args = (Object[])objectInputStream.readObject();
		
		
		/**
		 * It is parsed from the input stream. Who passed this id to me? I read this id
		 * 	Didn't we just send a binary corresponding to an integer with id 221 to the client, and then turn this binary into a byte array
		 * Next, let's use readInt() to convert the byte array representing 221 into an id of type int
		 */
		//int id = dataInputStream.readInt();
		PilliowServiceImpl serviceImpl = new PilliowServiceImpl();
		/**
		 * getPilliowByUPilliowId()This method or the class of this method is one of our services for others to call
		 * 
		 * The idea of calling the service is: I want to check the person with ID 221. Does my client have to write the id=221 to the server first
		 * Then, after the server finds this person, it turns it into binary and gives it to me, and the client returns it (writes it back)
		 * After I receive it, I will analyze it. On the server side, I get the id value, and then I can find a corresponding Pilliow
		 */
		
		/**
		 * The server receives the method name, parameter type and parameter of the method sent by the client (for a method, this is not complete)
		 */
		Method method = serviceImpl.getClass().getMethod(methodName, parameterTypes);
		Pilliow pilliow = (Pilliow) method.invoke(serviceImpl, args);
		
		//Pilliow pilliow = serviceImpl.getPilliowByPilliowId(id);
		/**
		 * Write down the pilliow you get
		 * 	In fact, I stole a lazy here, because I know that you have only two attributes, id and clothesColor. Writing these two attributes to you is equivalent to writing the Pilliow object to you
		 */
		dataOutputStream.writeInt(pilliow.getId());
		dataOutputStream.writeUTF(pilliow.getClothesColor());
		dataOutputStream.flush();
		
	}
}

/**
 * Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
 */
package server;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

import org.checkerframework.checker.units.qual.s;

import com.sun.org.apache.bcel.internal.generic.RETURN;

import entity.Pilliow;

/**
 * Encapsulate a Proxy, and others only need to understand it or call the getpilliowbypid method. I want to make an appointment with someone else's name, but I don't want to make an appointment with someone else's name
 * @author HuHongBo
 * @version 2022 May 12
 */
public class Stub {
	/**
	 * The client calls the implementation class of the server through this interface
	 * @param id
	 * @return
	 * @author HuHongBo
	 */
//    public Pilliow getPilliowByPilliowId(Integer id) throws Exception{
//    	/**
//    	 * Connect the network, write out the 221 value of id to the server, and ask him to help find pilot by id
//    	 */
//    	Socket socket = new Socket("127.0.0.1", 2221);
//    	ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//    	DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//    	dataOutputStream.writeInt(221);
//    	
//    	/**
//    	 * Convert the binary representing the ID value of 221 into a real int byte array, and then pass The write method writes out the byte array, and then the byte array, that is, id=221, can be sent to the server
//    	 */
//    	socket.getOutputStream().write(byteArrayOutputStream.toByteArray());
//    	socket.getOutputStream().flush();
//    	
//    	/**
//    	 * He stole a lazy from the server. Although there is a more advanced way to give me some of the pilot, now he is lazy and only writes the two attributes of the pilot
//    	 * Then my client DataInputStream is blocked here, waiting to read the pilot object sent from the server
//    	 */
//    	DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//    	/**
//    	 * Nonsense, since you are lazy, pass two attributes, and I'll read in id and clothesColor respectively
//    	 */
//    	int receivedId = dataInputStream.readInt();
//    	String clothesColor = dataInputStream.readUTF();
//    	Pilliow pillow = new Pilliow(receivedId, clothesColor);
//    	
//    	dataOutputStream.close();
//    	socket.close();
//    	return pillow;
	/**
	 * The key point of the dynamic proxy is to look at the return value first, that is, I will return the interface you want (the class that dynamically generates the interface through the dynamic proxy) to the specific proxy class of the interface you implemented (look at the return value).
	 * 
	 * 		Now we use dynamic proxy to generate a new class that implements our server interface
	 * The advantage of this writing is that when we add any method to the PilliowService in the future, when these methods are called, they will be processed by the calling processor of the dynamic agent with its own invoke method (the method processing method, the calling processor processes the code in the called or proxied method) (equivalent to generating a new proxy class that implements the server interface)
	 * 
	 * Version04:It should be emphasized that no matter which method it is (there is more than one method that can receive integer id values and other types of values)
	 * 			In essence, the name of a method is just a string, so let's transfer the names of dynamically generated or other methods we want to transfer through remote transmission
	 * @return
	 * @author HuHongBo
	 */
	public static PilliowService getStub(){
		InvocationHandler handler = new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				/**
		    	 * Connect the network, write out the 221 value of id to the server, and ask him to help find pilot by id
		    	 */
		    	Socket socket = new Socket("127.0.0.1", 2221);
		    	
		    	ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
		    	
		    	String methodName = method.getName();
		    	/**
		    	 * With the method name, we are afraid of method overloading, so in order to prevent duplication caused by overloading, we also get the parameter type of the called method
		    	 */
		    	Class[] parameterTypes = method.getParameterTypes();
		    	/**
		    	 * Write the method name, parameter type and parameters to be called to the server, and the server will know which method to call
		    	 */
		    	objectOutputStream.writeUTF(methodName);
		    	objectOutputStream.writeObject(parameterTypes);
		    	objectOutputStream.writeObject(args);
		    	objectOutputStream.flush();
		    	
		    	
		    	
		    	
		    	
//		    	ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//		    	DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//		    	dataOutputStream.writeInt(221);
//		    	
//		    	/**
//		    	 * Convert the binary representing the ID value of 221 into a real int byte array, and then pass The write method writes out the byte array, and then the byte array, that is, id=221, can be sent to the server
//		    	 */
//		    	socket.getOutputStream().write(byteArrayOutputStream.toByteArray());
//		    	socket.getOutputStream().flush();
		    	
		    	/**
		    	 * He stole a lazy from the server. Although there is a more advanced way to give me some of the pilot, now he is lazy and only writes the two attributes of the pilot
		    	 * Then my client DataInputStream is blocked here, waiting to read the pilot object sent from the server
		    	 */
		    	DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
		    	/**
		    	 * Nonsense, since you are lazy, pass two attributes, and I'll read in id and clothesColor respectively
		    	 */
		    	int id = dataInputStream.readInt();
		    	String clothesColor = dataInputStream.readUTF();
		    	Pilliow pilliow = new Pilliow(id, clothesColor);
		    	
		    	objectOutputStream.close();
		    	socket.close();
		    	//The server returns XXX to the client after processing according to the requirements of the client and the information transmitted by the client
		    	return pilliow;
			}
		};
		/**
		 * Proxy.newProxyInstance()What's wrong with new? It's just that new has an agent class
		 * 		This proxy class has several parameters:
		 * 			The first parameter is the ClassLoader that generates the proxy class
		 * 			The second parameter refers to the interfaces implemented by the proxy class (which interfaces are implemented? Don't you count them in your mind? You have to express this layer of relationship, that is, you have implemented the interface, to generate the proxy class of the sub implementation class of the interface)
		 * 			The third parameter is that I want to call the method in the proxy class generated dynamically through the dynamic proxy. I can only use the third parameter handler to enhance our original method, that is, add fuel and vinegar
		 * 				Specifically, how to enhance the third parameter is because the InvocationHandler is also an interface. Like the class, your interface still implements the functions through the methods in your stomach, and the InvocationHandler interface is enhanced through the invoke() method in your stomach
		 * 					The invoke() method in the third parameter also has three parameters:
		 * 						The first parameter is: who is calling my proxy object and whom I want to enhance
		 * 						The second parameter is: which method in the proxy class is being called (generated dynamically through the dynamic proxy)
		 * 						The third parameter is: which method in the proxy class is being called (generated dynamically through the dynamic proxy) and what parameters of this method have been passed in
		 */
		/**
		 * This object is a new object generated by our agent
		 */
		Object object = Proxy.newProxyInstance(PilliowService.class.getClassLoader(), new Class[]{PilliowService.class}, handler);
		/**
		 * The print result is com sun. proxy.$ Proxy0, this class is obviously generated dynamically. Where have we written this class
		 */
		System.out.println(object.getClass().getName());
		/**
		 * The print result is: interface server Pilliowservice indicates that the class generated dynamically by our dynamic agent inherits the server interface we wrote. (why do we need [0] when printing, because it is possible that the agent class generated by someone else's dynamic agent inherits more than one class. Who knows at the bottom)
		 */
		System.out.println(object.getClass().getInterfaces()[0]);
		return (PilliowService)object;
	}
}

But the defect remains at this time: remember, our current client needs to call the method of the remote server to get the pilliow through the id, but when we find the pilliow on the server side, we disassemble the pilliow into one member object or attribute in the object and pass it to us, and our client side also takes one member attribute after another as a complete object, This is obviously wrong. How can an object be equivalent to a bunch of member variables? therefore

So version 05 came into being
... to be continued

Tags: Java rpc Dynamic Proxy

Posted by tamilmani on Fri, 20 May 2022 00:56:03 +0300