Reflection, jdk dynamic proxy, rpc

Posted by winkhere on Fri, 14 Jan 2022 08:19:47 +0100

reflex

Reflection is one of the characteristics of Java programming language. It allows running Java programs to check themselves, or "self audit", and can directly operate the internal properties and methods of the program.

Some classes of reflection

Field class: represents the object properties obtained in reflection

Constructor class: represents the constructor of the class obtained in reflection

Method class: represents the method of the class obtained in reflection

Class: class object

Usage example of reflection

student class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
}

Reflection test class

public class ReflectionTest {
    @Test
    public void test1() throws Exception{
        Student c = new Student("Zhang San", 22);
        final Class<?> clazz = Class.forName("com.Student");
        //Get the public property of the class. If the property is not public, it cannot be obtained
        final Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("----------------------All properties----------------------");
        //Get all the properties of the class, including the properties decorated with private
        final Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }
        System.out.println("----------------------All methods----------------------");
        //Get all the methods of the class, including the methods decorated with private
        final Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());
        }
        System.out.println("----------------------Gets the specific value of the object property----------------------");
        final Field age = clazz.getDeclaredField("age");
        //When this property is set to true, you can operate on the properties of the object
        age.setAccessible(true);
        System.out.println(c);
        age.set(c,1111);
        System.out.println(c);
        System.out.println(age.get(c));
        //Construct objects by construction method
        final Object o = clazz.newInstance();
        System.out.println(o);
        //Get construction method
        final Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.toString());
        }
    }
}

jdk dynamic agent

proxy pattern

Definition of proxy pattern in head first design pattern: proxy pattern provides a substitute or placeholder for another object to control access to this object.

Static proxy

//Rental interface
public interface RentAble {

    void rent();
    
}
//Landlord class
public class Landlord implements RentAble{
    @Override
    public void rent() {
        System.out.println("Rental housing!!!");
    }
}
//Intermediary class
public class Intermediary implements RentAble{

    private RentAble rentAble;

    public Intermediary(RentAble rentAble) {
        this.rentAble = rentAble;
    }

    @Override
    public void rent() {
        System.out.println("Show people the house!!!");
        rentAble.rent();
    }
}

In this example, when we call the interface, we only need to call the rental method of the intermediary class to complete the rental, which is also called static proxy.

Dynamic agent

In fact, dynamic proxy is to dynamically generate the mediation class in the above example by the jvm according to reflection and other mechanisms when the program is running. The relationship between proxy class and delegate class is determined only when the program is running.

public static void main(String[] args) {
    RentAble landlord=new Landlord();
    RentAble rentAble = (RentAble) Proxy.newProxyInstance(Landlord.class.getClassLoader(), new Class[]{RentAble.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Show people the house!!!");
            Object invoke = method.invoke(landlord,args);
            return invoke;
        }
    });
    rentAble.rent();
}

RPC

RPC (Remote Procedure Call) Remote Procedure Call protocol

In fact, rpc is also implemented based on dynamic agent. We can send the interface, method name, method parameters and other information we need to call to another computer through the network. The other computer calls its local method according to the information we send, and then transmits the returned parameters to us.

Code required by the client

Client get proxy object

public class Stub {

    /**
     * Get proxy object
     * @param clazz Interface to get
     * @return
     */
    public static Object getService(Class clazz) {
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //Connect to remote server
                Socket socket = new Socket("127.0.0.1", 4396);
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                //Send interface name, method name, method parameter type and method parameter list to remote
                objectOutputStream.writeUTF(clazz.getName());
                objectOutputStream.writeUTF(method.getName());
                objectOutputStream.writeObject(method.getParameterTypes());
                objectOutputStream.writeObject(args);

                //Receive return value
                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                Object o = objectInputStream.readObject();


                //Close flow
                objectOutputStream.close();
                socket.close();
                return o;
            }
        };
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);
    }
}

The interface that the client needs to call

public interface Service {

    /**
     * Get student object
     * @param id Student id
     * @return
     */
    Student queryStudentById(long id);

}

Entity class

public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    //Student id
    private long id;

    //Student age
    private int age;

    //Student name
    private String name;

    public long getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Client main function

public class Client {
    public static void main(String[] args) {
        Service service = (Service) Stub.getService(Service.class);
        Student student = service.queryStudentById(123);
        System.out.println(JSON.toJSONString(student));
    }
}

Code required by the server

//Server
public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(4396);
        while (true) {

            handle(serverSocket.accept());

        }
    }

    /**
     * Processing request method
     * @param socket Connect socket
     * @throws Exception
     */
    public static void handle(Socket socket) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        //Get parameters
        String clazzName = objectInputStream.readUTF();
        String methodName = objectInputStream.readUTF();
        Class[] paramTypes = (Class[]) objectInputStream.readObject();
        Object[] args = (Object[]) objectInputStream.readObject();

        //Get the service implementation class through spi
        Class<?> aClass = Class.forName(clazzName);
        ServiceLoader<?> serviceLoader = ServiceLoader.load(aClass);
        Object studentService = null;
        for (Object service : serviceLoader) {
            studentService = service;
        }
        if (studentService == null) {
            System.out.println("Service not found");
            return;
        }

        //Get the method to be called
        Method method = studentService.getClass().getMethod(methodName, paramTypes);
        Object invoke = method.invoke(studentService, args);

        //Send return value
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        objectOutputStream.writeObject(invoke);

        //Close flow
        objectInputStream.close();
        objectOutputStream.close();
    }
}

Called interface

Interface

public interface Service {

    /**
     * Get student object
     * @param id Student id
     * @return
     */
    Student queryStudentById(long id);

}

Interface implementation

public class StudentService implements Service{

    @Override
    public Student queryStudentById(long id) {
        Student student = new Student();
        student.setId(4396);
        student.setAge(27);
        student.setName("Zhang San");
        return student;
    }
}

Entity class

public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    //Student id
    private long id;

    //Student age
    private int age;

    //Student name
    private String name;

    public long getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

SPI profile

com.example.demo.rpc.StudentService

Topics: Java rpc Network Protocol