ProxyUtil
Usage
Using Dynamic Proxy in JDK to Implement Aspects
- We define an interface:
public interface Animal {
void eat();
}
- Define an implementation class:
public class Cat implements Animal {
@Override
public void eat() {
Console.log("Cat eats fish");
}
}
- We use the
TimeIntervalAspect
aspect to proxy the aforementioned object to calculate the execution time of the cat eating fish:
Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class);
cat.eat();
TimeIntervalAspect
is located in the cn.hutool.aop.aspects
package and extends from SimpleAspect
. The code is as follows:
public class TimeIntervalAspect extends SimpleAspect {
// TimeInterval is a timer implemented by Hutool
private TimeInterval interval = new TimeInterval();
@Override
public boolean before(Object target, Method method, Object[] args) {
interval.start();
return true;
}
@Override
public boolean after(Object target, Method method, Object[] args) {
Console.log("Method [{}] execute spend [{}]ms", method.getName(), interval.intervalMs());
return true;
}
}
The execution result is:
Cat eats fish
Method [cn.hutool.aop.test.AopTest$Cat.eat] execute spend [16]ms
After calling the proxy method, the IDE automatically completes the returned object as Cat, due to the JDK mechanism. Our return value must be the interface implemented by the proxy class, so we need to manually change the return value to Animal otherwise we will encounter a type conversion error.
Using Cglib to Implement Aspects
The benefit of using Cglib is that it is unnecessary to define an interface to apply aspects directly to an object, and the usage is identical:
- Include the Cglib dependency
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.7</version>
</dependency>
- Define a class with no interface (it can have an interface or not)
public class Dog {
public String eat() {
Console.log("dog eats meat");
}
}
Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class);
String result = dog.eat();
The execution result is:
dog eats meat
Method [cn.hutool.aop.test.AopTest$Dog.eat] execute spend [13]ms
Other Methods
ProxyUtil also provides some convenient methods forProxynewProxyInstance
method is encapsulated to provide generic return values and support for additional parameter types.
Principles of Operation
The creation of dynamic proxy objects assumes that the proxy object is named $Proxy0
:
- Dynamically generate a class based on the provided
interfaces
and implement the interfaces ininterfaces
. - Load the recently generated class into the JVM using the provided classloader. In other words, load the
$Proxy0
class. - Invoke the
$Proxy0($Proxy0)
constructor to create an instance of$Proxy0
and use theinterfaces
parameter to traverse all of its interface methods, generating implementation methods. The implementation of these methods is essentially to invoke the method of the target object using reflection. - Return an instance of
$Proxy0
to the client. - When the client calls a method on the proxy class, it is equivalent to calling the
InvocationHandler.invoke(Object, Method, Object[])
method.