Before we learn about agent, let’s first understand the meaning of agent

  1. Definition: A proxy object is provided to the target object, and the proxy object controls the reference to the target object
  2. Purpose: To indirectly access the target object by introducing proxy, and to prevent the uncertain complexity brought to the system by directly accessing the target object

Why are there agents?

In traditional object-oriented thinking, if you want to achieve functional reuse, either inheritance or reference, either way, the code has a certain degree of intrusion, coupling is inevitable

Invasive meaning:

If you want to use it to enhance your program, you have to change your program code, and it’s invasive! It’s fine if only one or two features need to be enhanced, but if there are a lot of feature points that need to be enhanced, it’s a lot of work and the code isn’t elegant! Imagine if you exposed a set of interfaces to the public, and all of a sudden the leader said, interfaces need permission control. Where to add? The dumbest thing to do, of course, is to write a program that validates the logic and then calls every interface. This is also the short board of object-oriented thinking, in order to add some general functions for the program, can only be carried out through coupling. Proxy (dynamic proxy) can solve this problem!

Static versus dynamic proxies

Agents can be divided into static agents and dynamic agents according to the loading time of the proxied class.

  • Static proxy: The proxied class is determined at compile time
  • Dynamic proxy: The runtime determines which class is being proxied

Static proxy usage

1, static proxy to achieve the method

public interface Subject {

    void sayGoodBye(a);

    void sayHello(String str);

    boolean isProxy(a);
}

Copy the code

2, define the proxy class (original function class) and implement the proxy class function logic (dead do not change the kind of)

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

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

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

public class ProxySubject implements Subject {
    private Subject subject;

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

    @Override
    public void sayGoodBye(a) {
        SayGoodBye can do things before calling sayGoodBye (such as whether permission authentication can be called)
        System.out.println("ProxySubject sayGoodBye begin " +
                "Proxy class, enhanced functionality that sayGoodBye can do before calling (such as whether permission authentication can be called)");
        // Indirectly access the proxied object's methods in the methods of the proxy class
        subject.sayGoodBye();
        System.out.println("ProxySubject sayGoodBye end " +
                "Here you can handle the logic after the original method call.");
    }

    @Override
    public void sayHello(String str) {
        SayHello can do operations (such as whether permission authentication can be invoked) and test methods with arguments before calling sayHello
        System.out.println("ProxySubject sayHello begin " +
                "Proxy class, enhanced functionality that sayHello can do before calling (such as whether permission authentication can be called)");
        // Indirectly access the proxied object's methods in the methods of the proxy class
        subject.sayHello(str);
        System.out.println("ProxySubject sayHello end " +
                "Here you can handle the logic after the original method call.");
    }

    @Override
    public boolean isProxy(a) {
        IsProxy can perform operations (such as whether permission authentication can be called) and test methods with returns before calling isProxy
        System.out.println("ProxySubject isProxy begin " +
                "Proxy class, enhanced functionality isProxy can do operations before calling (such as whether permission authentication can be called)");
        boolean boolReturn = subject.isProxy();
        System.out.println("ProxySubject isProxy end " +
                "Here you can handle the logic after the original method call.");
        returnboolReturn; }}Copy the code

4, static proxy use

public class ProxyMain {

    public static void main(String[] args) {
        In some cases, we don't want to modify existing code. We use proxies to access objects indirectly
        RealSubject realSubject = new RealSubject();
        // Proxy objects, pass in objects that the original code does not want to modify
        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(); }}Copy the code

5. Final print

ProxySubject sayGoodBye Begin proxy class, SayGoodBye ProxySubject sayGoodBye End sayGoodBye ProxySubject sayGoodBye End sayGoodBye ProxySubject sayGoodBye End ****** ProxySubject sayHello begin Proxy class, SayHello Test ProxySubject sayHello End sayHello Test ProxySubject sayHello End sayHello Test ProxySubject sayHello End sayHello ****** ProxySubject isProxy begin Proxy class, RealSubject isProxy ProxySubject isProxy End here can handle the logic processing after the original method is calledCopy the code

6. Conclusion:

Static proxy (traditional proxy mode) implementation is more violent and direct, need to write all the proxy classes of all methods, and one by one to manually forward the past, troublesome and tedious. So we are going to learn and use dynamic proxies.

Core principles of dynamic proxy

There are two important classes or interfaces in Java’s dynamic proxy mechanism

  • One is that the InvocationHandler(Interface) needs to implement that Interface in your code
  • One is Proxy(Class)

2. InvocationHandler (Interface

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
Copy the code
  • Proxy: indicates the generated proxy object.
  • Method: Refers to a method object of the real object we want to call;
  • Args: refers to arguments accepted when a method of the real object is called;
  • Return value Object: the method called by the proxy needs to be returned intact

3. Core principle of Proxy (Class)

  • When compiled, the class of the Proxy object does not exist. When the proxy. newProxyInstance method is called, a class bytecode of Proxy0 is constructed and loaded into memory

4, Proxy. NewProxyInstance method details

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader, Class
       [] interfaces, InvocationHandler h)
        throws IllegalArgumentException
    {....}
Copy the code
  • Loader: A ClassLoader object that defines which ClassLoader object loads the generated proxy object
  • Interfaces: an array of Interface objects that represent the set of interfaces I am going to provide to the object THAT I want to delegate. If I provide interfaces to it, the proxy object claims to implement that Interface (polymorphic) so that I can call methods in that set of interfaces
  • An InvocationHandler object that represents which InvocationHandler object the dynamic proxy object is associated with when calling a method.

Dynamic proxy usage

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

public interface Subject {

    void sayGoodBye(a);

    void sayHello(String str);

    boolean isProxy(a);
}

Copy the code

Step 2: Define the real object (proxy class, never change) :

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

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

Step 3: Define an InvocationHandler, which is equivalent to a proxy handler

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

    Constructor that assigns an initial value to the real object we want to proxy
    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 propping up the real object
        System.out.println("Before Method invoke proxy class, function enhanced before calling"+method+"Actionable actions (such as whether permission authentication can be invoked)");
        System.out.println("Method:" + method);
        // When a proxy object calls a method of the real object, it automatically jumps to the invoke method of the handler object associated with the proxy object to invoke the corresponding return value, and finally returns the corresponding return value
        Object obj = method.invoke(subject, args);
        // We can also add some operations of our own after the real object is propped up
        System.out.println("After Method invoke here can handle the logic after the original Method call");
        returnobj; }}Copy the code

Step 4: Invoke

public class ProxyMain {

    public static void main(String[] args) {


        // Proxy class
        Subject realSubject = new RealSubject();
        // We pass the object to the class we want to proide, and finally call its methods through the proided object
        SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
        // Generate the proxy class
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);
        // Outputs proxy objects
        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 sayHello method of the proxy class
        subject.sayHello("Test");
        System.out.println("-- -- -- -- -- -- -- --");
        System.out.println("---subject.isProxy()-----"+ subject.isProxy()); }}Copy the code

Final print:

Proxy : com.sun.proxy.$Proxy0
Proxy super: java.lang.reflect.proxy Proxy interfaces: StaticProxy.Subject before Method invoke Proxy classes that enhance functionality before invokingpublic abstract voidStaticproxy. Subject. SayGoodBye () to do operation (such as whether to call the permissions authentication) Method:public abstract voidStaticproxy. Subject. SayGoodBye () RealSubject I sayGoodBye is intact code after Method invoke here can deal with the original Method call logic to handle after the -- -- -- -- -- -- -- -- before Method Invoke proxy class, function enhancement before callingpublic abstract voidStaticproxy. Subject. SayHello (Java. Lang. String) can do operations (such as whether it can call the access authentication) Method:public abstract voidStaticproxy. Subject. SayHello (Java. Lang. String) RealSubject I am intact code sayHello Test after Method can invoke this logic to handle after dealing with the original Method call -------- before Method invoke proxy class, function enhanced before callingpublic abstract booleanStaticproxy. Subject. IsProxy () to do operation (such as whether to call the permissions authentication) Method:public abstract booleanRealSubject staticproxy. Subject. IsProxy () I was intact code isProxy after Method can invoke this logic to handle after dealing with the original Method call ---subject.isProxy()-----false
---subject.isProxy()-----false
Copy the code

Dynamic proxy summary

  • Dynamic proxies can add flexibility to programs, such as logical processing before and after method calls
  • Perfect for decoupling, dynamic proxies can separate the invocation layer from the implementation layer
  • Dynamic proxies do not require interface implementation classes
  • Dynamic proxies can address the flow of program execution (moving events to activities in the next section)

Project Address:Click on the download