Java--Detailed Dynamic Agent Mechanism

When learning Spring, we know that Spring has two main ideas, one is IoC, and the other is AOP. For IoC, dependency injection does not need to say much, and for the core AOP of Spring, we not only need to know how to pass AOP to meet our functions, we need to learn more about the underlying principle, and the principle of AOP is java's dynamic proxy mechanism, so this essay is a review of java's dynamic mechanism.

In java's dynamic proxy mechanism, there are two important classes or interfaces, one is InvocationHandler (Interface), the other is Proxy (Class), this class and interface is necessary to achieve our dynamic proxy. First, let's take a look at how the java API help documentation describes these two classes:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

Each dynamic proxy class must implement the InvocationHandler interface, and each instance of the proxy class is associated with a handler. When we call a method through the proxy object, the method call will be forwarded to the interface of InvocationHandler To invoke the invoke method. Let's take a look at the only invoke method of the interface of InvocationHandler :

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

We see that this method accepts a total of three parameters, so what do these three parameters represent?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy :   refers to the real object we are proxy 
method :   refers to the Method object 
args that we want to call a method of the real object :   refers to the parameters accepted when calling a method of the real object

If you do n’t understand it, we will explain these parameters in more depth through an example.

Next, let's take a look at the Proxy class:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 

The role of the Proxy class is to dynamically create a proxy object class, which provides many methods, but we use the most is the newProxyInstance method:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

The role of this method is to get a dynamic proxy object, which receives three parameters, let's take a look at the meaning of these three parameters:

Copy code
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader :   A ClassLoader object, which defines which ClassLoader object to load the generated proxy object

interfaces :   An array of Interface objects, which means that I will provide a set of interfaces for the objects I need to proxy. If I provide a set of interfaces to it, then the proxy object claims to implement the interface (polymorphism) So that I can call the methods in this set of interfaces

h :   An InvocationHandler object, which indicates which InvocationHandler object will be associated with when my dynamic proxy object calls a method
Copy code

Well, after introducing these two interfaces (classes), let's take a look at an example to see what our dynamic proxy model looks like:

First we define an interface of type Subject and declare two methods for it:

public interface Subject
{
    public void rent();
    
    public void hello(String str);
}

Then, define a class to implement this interface, this class is our real object, RealSubject class:

Copy code
public class RealSubject implements Subject
{
    @Override
    public void rent()
    {
        System.out.println("I want to rent my house");
    }
    
    @Override
    public void hello(String str)
    {
        System.out.println("hello: " + str);
    }
}
Copy code

Next, we have to define a dynamic proxy class. As mentioned earlier, each dynamic proxy class must implement the InvocationHandler interface, so our dynamic proxy class is no exception:

Copy code
public class DynamicProxy implements InvocationHandler
{
    //  This is the real object we want to proxy 
    private Object subject;
    
    //     Construction method, assign initial value to the real object we want to proxy 
    public DynamicProxy (Object subject)
    {
        this.subject = subject;
    }
    
    @Override
    public Object invoke(Object object, Method method, Object[] args)
            throws Throwable
    {
        //   We can add some of our own operations before proxying real objects 
        System.out.println ("before rent house" );
        
        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 call 
        method.invoke (subject, args);
        
        //   After proxying real objects, we can also add some of our own operations 
        System.out.println ("after rent house" );
        
        return null;
    }

}
Copy code

Finally, let's take a look at our Client class:

Copy code
public  class Client
{
    public static void main(String[] args)
    {
        //     The real object we want to proxy 
        Subject realSubject = new RealSubject ();

        //     Which real object we want to proxy, pass the object in, and finally, 
        InvocationHandler handler = new DynamicProxy (realSubject);

        /*
         * Proxy's newProxyInstance method to create our proxy object, let's take a look at its three parameters
         * The first parameter handler.getClass (). GetClassLoader (), here we use the ClassLoader object of the handler class to load our proxy object
         * The second parameter realSubject.getClass (). GetInterfaces (), the interface we provide for the proxy object is the interface implemented by the real object, indicating that I want to proxy the real object, so that I can call this group of interfaces Way
         * The third parameter handler, we associate this proxy object with the InvocationHandler object above
         */
        Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);
        
        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
    }
}
Copy code

Let's take a look at the output of the console first:

Copy code
$ Proxy0

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent()
I want to rent my house
after rent house

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
hello: world
after rent house
Copy code

Let ’s first take a look at the $ Proxy0 thing. We see that this thing is printed by System.out.println (subject.getClass (). GetName ()); This is why we returned this proxy object The class name is like this?

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);

Maybe I thought the returned proxy object would be an object of type Subject, or an object of InvocationHandler, but the result is not. First, let's explain why we can convert it to an object of type Subject here? The reason is that on the second parameter of the newProxyInstance method, we provide a set of interfaces for the proxy object, then my proxy object will implement this set of interfaces, at this time we can of course convert the proxy object to mandatory type conversion For any one of this group of interfaces, because the interface here is of the Subject type, it can be converted to the Subject type .

At the same time, we must remember that the proxy object created by Proxy.newProxyInstance is an object dynamically generated when the jvm is running. It is not our InvocationHandler type nor the type of interface group we defined, but it is running. A dynamically generated object, and the naming method is in this form, starting with $, proxy is in, and the last number indicates the label of the object .

Then we take a look at these two sentences 

subject.rent();
subject.hello("world");

Here is the method of the kind of interface implemented through the proxy object. At this time, the program will jump to the invoke method in the handler associated with the proxy object to execute, and our handler object accepts a RealSubject. The type parameter indicates that it is this real object that I want to proxy, so at this time, the invoke method in the handler will be called to execute:

Copy code
public Object invoke(Object object, Method method, Object[] args)
            throws Throwable
    {
        //   We can add some of our own operations before proxying real objects 
        System.out.println ("before rent house" );
        
        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 call 
        method.invoke (subject, args);
        
        //   After proxying real objects, we can also add some of our own operations 
        System.out.println ("after rent house" );
        
        return null;
    }
Copy code

We see that when the method of the real object is called through the proxy object, we can add some of our own operations before and after the method, and we see that our method object is like this:

public  abstract  void com.xiaoluo.dynamicproxy.Subject.rent ()

public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)

It happens to be two methods in our Subject interface, which proves that when I call a method through a proxy object, it is actually delegated to be invoked by the invoke method of the handler object it is associated with, not by myself. Real call, but call through the agent.

This is our java dynamic proxy mechanism

 

This essay explains the dynamic proxy mechanism in java in detail. This knowledge point is very important, including our Spring AOP which is implemented through the dynamic proxy mechanism, so we must understand the dynamic proxy mechanism.


Published 7 original articles · 69 praises · 200,000+ views

Guess you like

Origin blog.csdn.net/u014320421/article/details/79770743