brief introduction
In JAVA, the agent mode is widely used and is often used in many frameworks or ordinary business. In fact, there is no mystery about the dynamic agent. As long as you understand the static agent, you can understand the dynamic agent immediately after in-depth thinking.
Static proxy
The proxy class generally has a common interface with the target class. The proxy class will not change the logic of the target class, but only do something before or after the behavior of the target class. Generally, we will not directly access the object with proxy class, but access its proxy class object.
For example:
My family has a white cat and likes to sleep every day. Now build a class
Cat interface:
public interface Cat { /** Sleep**/ void sleep(); }
White cat:
public class WhiteCat { void sleep() { ... } }
Now I want to record the sleeping time of the white cat every day. If your first thought is to modify the WhiteCat class directly
void sleep() { long start = System.currentTimeMillis(); ... long end = System.currentTimeMillis(); System.out.println(end - start); }
If you really think so, please learn the seven principles of design pattern again.
The more elegant way is to inherit.
public class WhiteCatTmp extends WhiteCat { void sleep() { long start = System.currentTimeMillis(); super.sleep(); long end = System.currentTimeMillis(); System.out.println(end - start); } }
It's OK to write like this, but it's only for white cats. The way of inheritance is not conducive to expansion. For example: now I have adopted several cats, and then I need to write a lot of WhiteCat tmp1, WhiteCat tmp2...
Is there a more elegant way to write? Cat objects are used directly without inheritance. No matter how many cats are adopted, as long as they are cats, they can be satisfied.
public class CatTmp implements Cat { private Cat cat; CatTmp(Cat cat) { this.cat = cat; } void sleep() { long start = System.currentTimeMillis(); cat.sleep(); long end = System.currentTimeMillis(); System.out.println(end - start); } }
Now it's common. As long as it's a cat, you can use this class. What does this have to do with agency? Wait a minute. I'll change my name.
public class CatProxy implements Cat { private Cat target; CatProxy(Cat cat) { this.target = cat; } void sleep() { long start = System.currentTimeMillis(); target.sleep(); long end = System.currentTimeMillis(); System.out.println(end - start); } }
This is the classic static proxy.
Dynamic agent
The proxy method created by the proxy class when the program is running is called dynamic proxy. CatProxy has been compiled before running, while dynamic proxy and proxy class are not defined in Java code, but dynamically generated according to our "instructions" in Java code at run time. Compared with static proxy, the advantage of dynamic proxy is that it can easily handle the functions of proxy classes in a unified way without modifying the methods in each proxy class.
for instance:
Cats unlock new skills
public interface Cat { /** Shit**/ void shit(); /** Food**/ void eat(); /** Sleep**/ void sleep(); }
If we create the proxy class manually, we need to modify the proxy class. If you use dynamic proxy, it won't be so troublesome.
class MyInvocationHandler implements InvocationHandler { Cat target; public MyInvocationHandler(Cat target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); method.invoke(target, args); long end = System.currentTimeMillis(); System.out.println(end - start); return null; } }
call
Cat whiteCat = new WhiteCat(); InvocationHandler handler = new MyInvocationHandler(whiteCat); Cat catProxy = (Cat) Proxy.newProxyInstance(whiteCat.getClass().getClassLoader(), whiteCat.getClass().getInterfaces(), handler); catProxy.shit(); catProxy.eat(); catProxy.sleep();
There are two kinds of dynamic agents in JAVA: one is built-in JDK (the above example), and the other is cglib based on asm.
The principle difference is as follows:
java dynamic proxy uses reflection mechanism to generate an anonymous class that implements the proxy interface. It calls InvokeHandler before calling the specific method.
cglib dynamic proxy uses asm open source package to load the class file of proxy object class and generate subclasses by modifying its bytecode.
Scene and selection:
If the target object implements the interface, the dynamic agent of JDK will be used to implement AOP by default
If the target object implements the interface, you can force the use of CGLIB to implement AOP
If the target object does not implement the interface, the CGLIB library must be used
What is the difference between JDK dynamic proxy and CGLIB bytecode generation?
JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes
CGLIB implements a proxy for a class. It mainly generates a subclass of a specified class and overrides the methods in it. Because it is inheritance, it is better not to declare this class or method as final.
The next article will explain the Proxy class in JDK.