Detailed explanation of Android static agent and dynamic agent

Before we learn about agency, we first understand the meaning of agency

  1. Definition: provide a proxy object to the target object, and the proxy object controls the reference of the target object
  2. Objective: to indirectly access the target object by introducing an agent to prevent the uncertain complexity of the system caused by direct access to the target object

Static agent and dynamic agent

According to the different time of loading the proxy class, the proxy is divided into static proxy and dynamic proxy.

  • Static proxy: the class to be proxy is determined at compile time
  • Dynamic proxy: the runtime determines which class to proxy

Static proxy usage

1. Methods to be implemented by static agent

public interface Subject {

    void sayGoodBye();

    void sayHello(String str);

    boolean isProxy();
}

2. Define the proxy class (the original function class) and implement the function logic of the proxy class (the one that doesn't change)

public class RealSubject implements Subject {
    @Override
    public void sayGoodBye() {
        System.out.println("RealSubject I'm the original code sayGoodBye ");
    }
    @Override
    public void sayHello(String str) {
        System.out.println("RealSubject I'm the original code sayHello  " + str);
    }

    @Override
    public boolean isProxy() {
        System.out.println("RealSubject  I'm the original code    isProxy     ");
        return false;
    }
}

3. Define a static proxy class (function addition class). This proxy class must also implement the same Subject interface as the proxy class to facilitate the enhancement of the original functions

public class ProxySubject implements Subject {
    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void sayGoodBye() {
        //Agent class, function enhancement, sayGoodBye can do operations before calling (such as whether the authority authentication can be called)
        System.out.println("ProxySubject sayGoodBye begin  " +
                "Proxy class, function enhancement, before call sayGoodBye Do operations (such as whether you can call permission authentication)");
        //The method that indirectly accesses the proxied object in the method of the proxy class
        subject.sayGoodBye();
        System.out.println("ProxySubject sayGoodBye end " +
                "Here you can handle the logical processing after the original method call");
    }

    @Override
    public void sayHello(String str) {
        //Proxy class, function enhancement, sayHello can do operations before calling (such as whether the permission authentication can be called) and test the methods with parameters
        System.out.println("ProxySubject sayHello begin  " +
                "Proxy class, function enhancement, before call sayHello Do operations (such as whether you can call permission authentication)");
        //The method that indirectly accesses the proxied object in the method of the proxy class
        subject.sayHello(str);
        System.out.println("ProxySubject sayHello end " +
                "Here you can handle the logical processing after the original method call");
    }

    @Override
    public boolean isProxy() {
        //Proxy class, function enhancement isProxy can do operations before calling (such as whether the permission authentication can be called) and test the method with return
        System.out.println("ProxySubject isProxy begin  " +
                "Proxy class, function enhancement, before call isProxy Do operations (such as whether you can call permission authentication)");
        boolean boolReturn = subject.isProxy();
        System.out.println("ProxySubject isProxy end " +
                "Here you can handle the logical processing after the original method call");
        return boolReturn;
    }
}

4. Static proxy usage

public class ProxyMain {

    public static void main(String[] args) {
        //In some cases, we do not want to modify the existing code for the proxy object. We use the proxy to access it indirectly
        RealSubject realSubject = new RealSubject();
        //Proxy class object, transfer the object that the original code does not want to modify into the proxy class object
        ProxySubject proxySubject = new ProxySubject(realSubject);
        //Call the method of the proxy class object
        proxySubject.sayGoodBye();
        System.out.println("******");
        proxySubject.sayHello("Test");
        System.out.println("******");
        proxySubject.isProxy();
    }

}

5. Final printing

ProxySubject sayGoodBye begin  Proxy class, function enhancement, before call sayGoodBye Do operations (such as whether you can call permission authentication)

RealSubject I'm the original code sayGoodBye 

ProxySubject sayGoodBye end Here you can handle the logical processing after the original method call

******

ProxySubject sayHello begin  Proxy class, function enhancement, before call sayHello Do operations (such as whether the authority authentication can be invoked)

RealSubject I'm the original code sayHello  Test

ProxySubject sayHello end Here you can handle the logical processing after the original method call

******

ProxySubject isProxy begin  Proxy class, function enhancement, before call isProxy Do operations (such as whether you can call permission authentication)

RealSubject  I'm the original code    isProxy  

ProxySubject isProxy end Here you can handle the logical processing after the original method call   

6. Summary:

The implementation of static proxy (traditional proxy model) is more violent and direct. It is necessary to write all the methods of all the proxy classes and manually forward them one by one, which is cumbersome and cumbersome. So we need to learn and use dynamic agents.

Core principles of dynamic agent

1. In the dynamic proxy mechanism of java, there are two important classes or interfaces

  • One is the InvocationHandler(Interface), which needs to be implemented in the code
  • One is Proxy(Class)

2. InvocationHandler (Interface) details

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
  • Proxy: refers to the generated proxy object;
  • Method: refers to the method object of a method of the real object we want to call;
  • args: refers to the parameters accepted when calling a method of a real object;

3. Core principle of Proxy (Class)

  • When compiling, the class of the proxy object does not exist. When you need to call proxy When using the newproxyinstance method, a class bytecode of Proxy0 will be constructed and loaded into memory

4,Proxy. Detailed explanation of newproxyinstance method

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {....}
  • loader: a ClassLoader object that defines which ClassLoader object loads the generated proxy object
  • Interfaces: an array of Interface objects, which indicates what set of interfaces I will provide to the object I need to proxy. If I provide a set of interfaces to it, the proxy object claims to implement the Interface (polymorphic), so that I can call the methods in this set of interfaces
  • An InvocationHandler object indicates which InvocationHandler object will be associated when I call the method as a dynamic proxy object.

Dynamic proxy usage

Step 1: define an interface (logic to be implemented)

public interface Subject {

    void sayGoodBye();

    void sayHello(String str);

    boolean isProxy();
}

Step 2: define the real object (the proxy class, the one that doesn't change after being killed):

public class RealSubject implements Subject {
    @Override
    public void sayGoodBye() {
        System.out.println("RealSubject I'm the original code sayGoodBye ");
    }
    @Override
    public void sayHello(String str) {
        System.out.println("RealSubject I'm the original code sayHello  " + str);
    }

    @Override
    public boolean isProxy() {
        System.out.println("RealSubject  I'm the original code    isProxy     ");
        return false;
    }
}

Step 3: define an InvocationHandler, which is equivalent to a proxy processor

public class SubjectInvocationHandler implements InvocationHandler {
    //This is the real object we want to represent
    private Object subject;

    //The construction method assigns the initial value to the real object we want to represent
    public SubjectInvocationHandler(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        //We can add our own operations before representing real objects
        System.out.println("before Method invoke  Proxy class, function enhancement, before call "+method+" Do operations (such as whether you can call permission authentication)");
        System.out.println("Method:" + method);
        //When the proxy object calls the method of the real object, it will automatically jump to the invoke method of the handler object associated with the proxy object to get the corresponding return value, and finally return the corresponding return value
        Object obj = method.invoke(subject, args);
        //After representing the real object, we can also add some of our own operations
        System.out.println("after Method invoke  Here you can handle the logical processing after the original method call ");
        return obj;
    }
}

Step 4: call

public class ProxyMain {

    public static void main(String[] args) {


        //Proxy class
        Subject realSubject = new RealSubject();
        //We pass the object into the class we want to proxy, and finally call its method through the proxy object
        SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
        //Generate proxy class
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);
        //Output proxy class object
        System.out.println("Proxy : " + subject.getClass().getName());
        System.out.println("Proxy super : " + subject.getClass().getSuperclass().getName());
        System.out.println("Proxy interfaces : " + subject.getClass().getInterfaces()[0].getName());
        //Call the sayGoodBye method of the proxy class
        subject.sayGoodBye();
        System.out.println("--------");
        //Call the proxy class sayHello method
        subject.sayHello("Test");
        System.out.println("--------");
        System.out.println("---subject.isProxy()-----" + subject.isProxy());
    }

}

Final print:

Proxy : com.sun.proxy.$Proxy0
Proxy super : java.lang.reflect.Proxy
Proxy interfaces : staticproxy.Subject
before Method invoke  Proxy class, function enhancement, before call public abstract void staticproxy.Subject.sayGoodBye() Do operations (such as whether you can call permission authentication)
Method:public abstract void staticproxy.Subject.sayGoodBye()
RealSubject I'm the original code sayGoodBye 
after Method invoke  Here you can handle the logical processing after the original method call 
--------
before Method invoke  Proxy class, function enhancement, before call public abstract void staticproxy.Subject.sayHello(java.lang.String) Do operations (such as whether you can call permission authentication)
Method:public abstract void staticproxy.Subject.sayHello(java.lang.String)
RealSubject I'm the original code sayHello  Test
after Method invoke  Here you can handle the logical processing after the original method call 
--------
before Method invoke  Proxy class, function enhancement, before call public abstract boolean staticproxy.Subject.isProxy() Do operations (such as whether you can call permission authentication)
Method:public abstract boolean staticproxy.Subject.isProxy()
RealSubject  I'm the original code    isProxy     
after Method invoke  Here you can handle the logical processing after the original method call 
---subject.isProxy()-----false
---subject.isProxy()-----false

Dynamic agent summary

  • Dynamic proxy can increase the flexibility of the program, such as the logical processing before and after calling the method
  • To solve the decoupling problem perfectly, dynamic agent can separate the calling layer from the implementation layer
  • Dynamic proxies do not require interface implementation classes
  • Dynamic agent can solve the process of program execution (the event in the next installment will be transferred to activity execution)

Project address: Click download

Keywords: Android

Added by rushdot on Sat, 22 Jan 2022 09:53:00 +0200