In the chapter on how to achieve AOP (on) introduced
Agency model
The root of the dynamic proxy is the proxy mode in the design pattern . The description of the proxy mode in GoF is as follows:
Provide a surrogate or placeholder for another object to control access to it.
It can be seen from its definition that the proxy mode is mainly to control the access of the object, and usually also has all the functions of the proxy. Through the proxy mode, we can add some functions to the proxy class by introducing the proxy class without changing the proxy class. At this time, a famous sentence in the computer science community floats in our minds (PS basic knowledge is very important, you can see this ):
Any problem in computer science can be solved by adding an intermediate layer.
In fact, the agency model is often encountered in real life. For example, when renting a house in first-tier cities, most of them are renting agencies to look at the house, negotiate the price, and sign the contract, because the landlord of the house has fully entrusted the house to it. The intermediary dealt with it. The renting intermediary here is actually acting as a solution to the agency object in the agency model, and the real agent (target object) is actually the landlord of the house, and we are all renting intermediaries (agent objects) when dealing with us. The structure of the proxy model class diagram is shown in the following figure:
The meaning of each part in the figure is as follows:
- ISubject is an abstraction of the capabilities provided by the proxy object.
- SubjectImpl is the specific implementation class of the agent.
- SubjectProxy is the proxy implementation class, usually this class holdsISubjectAn instance of the interface.
- Client is the abstract role of the visitor, to visitISubjectType of resource.
can be seen
In the proxy object (
Dynamic proxy
So far, everything is so beautiful. When only adding crosscutting logic to the same target object type, you only need to create a proxy object, but in
/**
* @author mghio
* @Since 2021-05-29
*/
public interface Subject {
void doOperation () ;
}
public class SubjectImpl implements Subject {
@Override
public void doOperation () {
System.out.println( "SubjectImpl doOperation..." );
}
}
public class JDKInvocationHandler implements InvocationHandler {
private final Subject target;
public JDKInvocationHandler(Subject target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//add pre process logic if necessary
System.out.println("Proxy before JDKInvocationHandler doOperation...");
Object result = method.invoke(target, args);
System.out.println("Proxy after JDKInvocationHandler doOperation...");
//add post process logic if necessary
return result;
}
}
public class Client {
public static void main (String[] args) {
//Save the generated proxy class in the root directory (com/sun/proxy/XXX.class)
System.setProperty( "sun.misc.ProxyGenerator.saveGeneratedFiles " , "true" );
Subject target = new SubjectImpl();
Subject proxy = (Subject) Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(),
new Class[]{Subject.class}, new JDKInvocationHandler(target));
proxy.doOperation();
}
}
Copy code
As can be seen from the above code, use
- Define the public interface SubjectTo create a proxy objectSubjectImpl
- Create the processing object of the proxied object JDKInvocationHandler, Holding the target audienceSubjectReference
- use JDKofProxyStatic method of classnewProxyInstanceCreate proxy object
By setting
public final class $ Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
static {
try {
m1 = Class.forName( "java.lang.Object" ).getMethod( "equals" , Class.forName( "java.lang.Object" ));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("cn.mghio.designpattern.proxy.dynamicproxy.Subject").getMethod("doOperation");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
public $Proxy0(InvocationHandler var1) throws {
super (var1);
}
public final void doOperation () throws {
try {
super .h.invoke( this , m3, (Object[]) null );
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//omit toString, equals, hashCode method...
}
Copy code
As can be seen from the code of the dynamically generated proxy class,
By default,
Bytecode generation technology
When the target object does not implement the interface, you can inherit the target object through dynamic bytecode generation to dynamically generate the corresponding subclass, in the generated subclass
/**
* @author mghio
* @Since 2021-05-29
*/
public class RealSubject {
public void doOperation () {
System.out.println( "RealSubject doOperation..." );
}
}
public class CglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
//add pre process logic if necessary
System.out.println("Cglib before RealSubject doOperation...");
Object result = methodProxy.invokeSuper(o, args);
System.out.println("Cglib after RealSubject doOperation...");
//add post process logic if necessary
return result;
}
}
public class Client {
public static void main(String[] args) {
//
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
"/Users/mghio/IdeaProjects/designpattern/cglib/proxy/");
//1. Enhancer
Enhancer enhancer = new Enhancer();
//2.
enhancer.setSuperclass(RealSubject.class);
//3. ( MethodInterceptor )
enhancer.setCallback(new CglibMethodInterceptor());
//4.
RealSubject proxy = (RealSubject) enhancer.create();
proxy.doOperation();
}
}
- Enhancer
- ( ) final
- ( MethodInterceptor)
- Enhanercreate()
JDK | CGLIB | |
---|---|---|
JDK Proxy | CGLIB Factory | |
final | final final | |
JDK |