This article brings you a brief introduction to InvocationHandler of Java dynamic proxy. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
There are very in-depth articles on the Internet about Java's dynamic proxy, Proxy and InvocationHandler concepts. In fact, these concepts are not that complicated. Now we understand what InvocationHandler is through the simplest example. It is worth mentioning that InvocationHandler is widely used in Spring framework implementation, which means that if we understand InvocationHandler thoroughly, we will lay a solid foundation for future Spring source code learning.
Develop an interface that contains two methods that can greet "hello" or "goodbye" to the specified person.
public interface IHello { void sayHello(String name); void sayGoogBye(String name); }
Create a simple class to implement this IHello interface.
public class Helloimplements implements IHello { @Override public void sayHello(String name) { System.out.println("Hello " + name); } @Override public void sayGoogBye(String name) { System.out.println(name+" GoodBye!"); } }
Consuming this implementation class is nothing special so far.
Now suppose we receive this requirement: The boss requires that every time the implementation class greets someone, the details of the greeting must be recorded in a log file. For the sake of simplicity, we print the following line of statement before greeting to simulate the logging action.
System.out.println("问候之前的日志记录...");
You may say, this is not simple? Directly modify the corresponding method of Helloimplements and insert this line of log into the corresponding method.
However, the boss’s request is that you are not allowed to modify the original Helloimplements class. In real scenarios, Helloimplements may be provided by a third-party jar package, and we have no way to modify the code.
You may say that we can use the proxy pattern in the design pattern, that is, create a new Java class as a proxy class, and also implement IHello interface and then pass an instance of the Helloimplements class into the proxy class. Although we are required not to modify the code of Helloimplements, we can write the logging code in the proxy class. The complete code is as follows:
public class StaticProxy implements IHello { private IHello iHello; public void setImpl(IHello impl){ this.iHello = impl; } @Override public void sayHello(String name) { System.out.println("问候之前的日志记录..."); iHello.sayHello(name); } @Override public void sayGoogBye(String name) { System.out.println("问候之前的日志记录..."); iHello.sayGoogBye(name); } static public void main(String[] arg) { Helloimplements hello = new Helloimplements(); StaticProxy proxy = new StaticProxy(); proxy.setImpl(hello); proxy.sayHello("Jerry"); } }
This approach can achieve the requirements:
Let’s look at how to use InvocationHandler to achieve the same effect. .
InvocationHandler是一个JDK提供的标准接口。看下面的代码: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynaProxyHello implements InvocationHandler { private Object delegate; public Object bind(Object delegate) { this.delegate = delegate; return Proxy.newProxyInstance( this.delegate.getClass().getClassLoader(), this.delegate .getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { System.out.println("问候之前的日志记录..."); // JVM通过这条语句执行原来的方法(反射机制) result = method.invoke(this.delegate, args); } catch (Exception e) { e.printStackTrace(); } return result; }
The bind method in the above code is very similar to the setImpl method of my previous proxy class StaticProxy, but the input parameter type of this bind method is more universal. The logging code is written in the method invoke.
See how to use it:
static public void main(String[] arg) { DynaProxyHello helloproxy = new DynaProxyHello(); Helloimplements hello = new Helloimplements(); IHello ihello = (IHello) helloproxy.bind(hello); ihello.sayHello("Jerry"); }
The execution effect is exactly the same as that of StaticProxy solution.
Let’s debug it first. When the bind method is executed, the method Proxy.newProxyInstance is called, and the instance of the Helloimplements class is passed in.
We observe the ihello variable returned by the statement IHello ihello = (IHello) helloproxy.bind(hello) in the debugger. Although its static type is IHello, please note that when observing its actual type in the debugger, it is not an instance of Helloimplements, but one processed by the JVM, including the line of log we handwritten in the invoke method. Document the code. The ihello type is $Proxy0.
When the sayHello method of this variable processed by the JVM is called, the JVM automatically transfers the call to DynaProxyHello.invoke:
So, in the invoke method, our handwritten logging code is executed, and then the original sayHello code is executed through Java reflection.
Some friends may ask, your InvocationHandler seems more complicated than the static proxy StaticProxy? what is the benefit?
Assume that the boss's needs have changed again, and different logging strategies should be used in the methods of calling greetings and saying goodbye.
Let’s see how to use InvocationHandler to implement it elegantly:
I hope this example can give everyone an understanding of Java’s dynamic proxy InvocationHandler. Get the most basic understanding.
The above is the detailed content of A brief introduction to InvocationHandler of Java dynamic proxy. For more information, please follow other related articles on the PHP Chinese website!