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:
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
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:
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); } }
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:
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; } }
Finally, let's take a look at our Client class:
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"); } }
Let's take a look at the output of the console first:
$ 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
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:
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; }
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.