mybatis的懶加載是用到了javassist的動(dòng)態(tài)代理洲鸠,所以想先簡(jiǎn)單說(shuō)一下這個(gè)进鸠,順便帶上cglib動(dòng)態(tài)代理人灼。
javassist動(dòng)態(tài)代理
這里我用的依賴(lài)
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
測(cè)試代碼:
package lnstark.test.testjavassistproxy;
import javassist.NotFoundException;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* by Lnstark
* 2021/12/18
*/
public class MyProxyFactory implements MethodHandler {
private Object target;
public MyProxyFactory(Object target) {
this.target = target;
}
/**
* 增強(qiáng)方法
*
* @param self 代理后的類(lèi)
* @param thisMethod 代理類(lèi)的tweet方法
* @param proceed 代理類(lèi)的_d8tweet方法
* @param args 方法參數(shù)
* @return 執(zhí)行結(jié)果
*/
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
System.out.println("before invoke");
// 還記得jdk動(dòng)態(tài)代理這里的傳參會(huì)是target
Object ret = proceed.invoke(self, args);
System.out.println("after invoke");
return ret;
}
static class Bird {
private String name;
public Bird(String name) {
this.name = name;
}
void tweet() {
System.out.println("my name is: " + name);
}
}
public static void main(String[] args) throws IOException, NotFoundException {
Bird bird = new Bird("百靈");
Bird proxy = null;
ProxyFactory enhancer = new ProxyFactory();
// 設(shè)置代理類(lèi)輸出路徑陆馁,實(shí)際的目錄還要帶上包名
// 如此類(lèi)的包名為lnstark.test.testjavassistproxy
// 那生成的.class文件所在目錄為 d:/lnstark/test/testjavassistproxy
enhancer.writeDirectory = "d:/";
// 需要代理的類(lèi)
enhancer.setSuperclass(Bird.class);
try {
// 生成代理對(duì)象
proxy = (Bird) enhancer.create(new Class[]{String.class}, new Object[]{"布谷"}, new MyProxyFactory(bird));
} catch (NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
proxy.tweet();
}
}
執(zhí)行結(jié)果:
before invoke
my name is: 布谷
after invoke
編譯后的動(dòng)態(tài)代理.class文件丟到idea里:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package lnstark.test.testjavassistproxy;
import java.io.ObjectStreamException;
import java.lang.reflect.Method;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyObject;
import javassist.util.proxy.RuntimeSupport;
import lnstark.test.testjavassistproxy.MyProxyFactory.Bird;
public class MyProxyFactory$Bird_$$_jvstae2_0 extends Bird implements ProxyObject {
private MethodHandler handler;
public static byte[] _filter_signature;
public static final long serialVersionUID;
private static Method[] _methods_;
public MyProxyFactory$Bird_$$_jvstae2_0(String var1) {
this.handler = RuntimeSupport.default_interceptor;
super(var1);
}
public final Object _d0clone() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
Method[] var1 = _methods_;
return (Object)this.handler.invoke(this, var1[0], var1[1], new Object[0]);
}
public final boolean _d1equals(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
Method[] var2 = _methods_;
return (Boolean)this.handler.invoke(this, var2[2], var2[3], new Object[]{var1});
}
public final void _d2finalize() throws Throwable {
super.finalize();
}
protected final void finalize() throws Throwable {
Method[] var1 = _methods_;
this.handler.invoke(this, var1[4], var1[5], new Object[0]);
}
public final int _d4hashCode() {
return super.hashCode();
}
public final int hashCode() {
Method[] var1 = _methods_;
return (Integer)this.handler.invoke(this, var1[8], var1[9], new Object[0]);
}
public final String _d7toString() {
return super.toString();
}
public final String toString() {
Method[] var1 = _methods_;
return (String)this.handler.invoke(this, var1[14], var1[15], new Object[0]);
}
public final void _d8tweet() {
super.tweet();
}
final void tweet() {
Method[] var1 = _methods_;
this.handler.invoke(this, var1[16], var1[17], new Object[0]);
}
static {
Method[] var0 = new Method[24];
Class var1 = Class.forName("lnstark.test.testjavassistproxy.MyProxyFactory$Bird_$$_jvstae2_0");
RuntimeSupport.find2Methods(var1, "clone", "_d0clone", 0, "()Ljava/lang/Object;", var0);
RuntimeSupport.find2Methods(var1, "equals", "_d1equals", 2, "(Ljava/lang/Object;)Z", var0);
RuntimeSupport.find2Methods(var1, "finalize", "_d2finalize", 4, "()V", var0);
RuntimeSupport.find2Methods(var1, "hashCode", "_d4hashCode", 8, "()I", var0);
RuntimeSupport.find2Methods(var1, "toString", "_d7toString", 14, "()Ljava/lang/String;", var0);
RuntimeSupport.find2Methods(var1, "tweet", "_d8tweet", 16, "()V", var0);
_methods_ = var0;
serialVersionUID = -1L;
}
public void setHandler(MethodHandler var1) {
this.handler = var1;
}
public MethodHandler getHandler() {
return this.handler;
}
Object writeReplace() throws ObjectStreamException {
return RuntimeSupport.makeSerializedProxy(this);
}
}
find2Methods方法:
public static void find2Methods(Class clazz, String superMethod,
String thisMethod, int index,
String desc, java.lang.reflect.Method[] methods)
{
methods[index + 1] = thisMethod == null ? null
: findMethod(clazz, thisMethod, desc);
methods[index] = findSuperClassMethod(clazz, superMethod, desc);
}
可以看出tweet是_methods_[16]宪摧,_d8tweet是_methods_[17]。
代理類(lèi)調(diào)用tweet方法氧骤,里面調(diào)用handler.invoke(即我們實(shí)現(xiàn)的方法)呻疹。
傳入?yún)?shù):代理類(lèi)本身,tweet方法语淘,_d8tweet方法和方法參數(shù)诲宇。
cglib動(dòng)態(tài)代理
引入包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
測(cè)試代碼:
package lnstark.test.testcglibproxy;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* by Lnstark
* 2021/12/19
*/
public class CglibProxy {
static class Bird {
private String name;
public Bird(String name) {
this.name = name;
}
void tweet() {
System.out.println("my name is: " + name);
}
}
static class MyInterceptor implements MethodInterceptor {
/**
*
* @param o 代理后的對(duì)象
* @param method Bird的原方法
* @param objects 方法參數(shù)
* @param methodProxy
* @return 方法返回
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before invoke " + method.getName());
// 這里用methodProxy而不是原始方法method
Object ret = methodProxy.invokeSuper(o, objects);
System.out.println("after invoke " + method.getName());
return ret;
}
}
public static void main(String[] args) {
Bird bird = new Bird("百靈");
// 指定生成的.class文件目錄
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/");
// 生成的步驟類(lèi)似javassist
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Bird.class);
enhancer.setCallback(new MyInterceptor());
Bird proxy = (Bird) enhancer.create(new Class[]{String.class}, new Object[]{"布谷"});
proxy.tweet();
}
}
結(jié)果:
before invoke tweet
my name is: 布谷
after invoke tweet
代理類(lèi)里會(huì)生成下面兩個(gè)方法,tweet方法里調(diào)用我們實(shí)現(xiàn)的intercept方法惶翻,里面執(zhí)行了methodProxy.invokeSuper(o, objects);底層是調(diào)用的這里的CGLIB$tweet$0方法姑蓝。
final void CGLIB$tweet$0() {
super.tweet();
}
final void tweet() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$tweet$0$Method, CGLIB$emptyArgs, CGLIB$tweet$0$Proxy);
} else {
super.tweet();
}
}