最近做了數(shù)據(jù)庫(kù)的主從分離绢要,使用了spring的aop,動(dòng)態(tài)代理遇到了很多問(wèn)題拗小,將源碼了解了一下重罪。
1、JDK代理
jdk代理使用到的類(lèi)主要有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler哀九。簡(jiǎn)單的demo是有一個(gè)接口 定義了一個(gè)方法剿配,然后一個(gè)被代理的類(lèi)實(shí)現(xiàn)了這個(gè)接口,重寫(xiě)了方法阅束。然后寫(xiě)一個(gè)Handler類(lèi)實(shí)現(xiàn)InvocationHandler接口呼胚,通過(guò)構(gòu)造函數(shù)傳入被代理類(lèi)實(shí)例,并重寫(xiě)InvocationHandler接口的invoke()方法息裸。
public interface GameInterface {
void login();
void exit();
}
public class GamePlay implements GameInterface {
@Override
public void login() {
System.out.println("login");
}
@Override
public void exit() {
System.out.println("exit");
}
}
public class MyInvocationHandler implements InvocationHandler {
Object obj = null;
public MyInvocationHandler(Object _obj) {
this.obj = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy do");
return method.invoke(this.obj, args);
}
}
public class Main {
public static void main(String[] args) throws Exception {
GamePlay gamePlay = new GamePlay();
InvocationHandler handler = new MyInvocationHandler(gamePlay);
ClassLoader cl = gamePlay.getClass().getClassLoader();
GameInterface proxy = (GameInterface) Proxy.newProxyInstance(cl, gamePlay.getClass().getInterfaces(), handler);
proxy.login();
proxy.exit();
//輸出代理后類(lèi)文件
byte[] classFile = ProxyGenerator.generateProxyClass("com.sun.proxy.$Proxy.1", gamePlay.getClass().getInterfaces());
FileOutputStream out = new FileOutputStream("com.sun.proxy.$Proxy.1.class");
out.write(classFile);
out.flush();
}
}
我們把代理后的文件看一下砸讳,這個(gè)可以直接將代理后的文件放到intellij的根目錄里面。
public final class 1 extends Proxy implements GameInterface {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public _/* $FF was: 1*/(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void exit() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void login() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.qyer.GameInterface").getMethod("exit", new Class[0]);
m4 = Class.forName("com.qyer.GameInterface").getMethod("login", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到代理后的類(lèi)繼承了Proxy類(lèi)界牡,并實(shí)現(xiàn)了我們的GameInterface接口簿寂,spring的aop裝入的bean就是代理后的這樣的類(lèi),這對(duì)后面我們分析遇到的問(wèn)題很有幫助宿亡。
2常遂、cglib
cglib主要使用到的類(lèi)是Enhancer和MethodInterceptor,需要引入依賴挽荠,在有spring環(huán)境編譯的話可以使用spring封裝的這兩個(gè)類(lèi)克胳。demo是我們有一個(gè)類(lèi)平绩,需要被代理,我們就復(fù)用上面那個(gè)類(lèi)GamePlay漠另,他的接口這里不使用捏雌。然后新建類(lèi)實(shí)現(xiàn)MethodInterceptor接口,重寫(xiě)intercept()方法笆搓。
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before do");
return methodProxy.invokeSuper(o, objects);
}
}
public class Main {
public static void main(String[] args) throws Exception {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhangrui/Desktop");
CglibProxy proxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
//設(shè)置代理類(lèi)
enhancer.setSuperclass(GamePlay.class);
//設(shè)置回調(diào)攔截
enhancer.setCallback(proxy);
GamePlay gameInterface = (GamePlay) enhancer.create();
gameInterface.login();
}
}
這樣就代理成功了性湿,然后我們還是將代理后的類(lèi)文件輸出查看。
public class GamePlay$$EnhancerByCGLIB$$d2a7d2f3 extends com.storm.cache.GamePlay implements org.springframework.cglib.proxy.Factory {
private boolean CGLIB$BOUND;
private static final java.lang.ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final org.springframework.cglib.proxy.Callback[] CGLIB$STATIC_CALLBACKS;
private org.springframework.cglib.proxy.MethodInterceptor CGLIB$CALLBACK_0;
private static final java.lang.reflect.Method CGLIB$exit$0$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$exit$0$Proxy;
private static final java.lang.Object[] CGLIB$emptyArgs;
private static final java.lang.reflect.Method CGLIB$login$1$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$login$1$Proxy;
private static final java.lang.reflect.Method CGLIB$finalize$2$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$finalize$2$Proxy;
private static final java.lang.reflect.Method CGLIB$equals$3$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$equals$3$Proxy;
private static final java.lang.reflect.Method CGLIB$toString$4$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$toString$4$Proxy;
private static final java.lang.reflect.Method CGLIB$hashCode$5$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$hashCode$5$Proxy;
private static final java.lang.reflect.Method CGLIB$clone$6$Method;
private static final org.springframework.cglib.proxy.MethodProxy CGLIB$clone$6$Proxy;
static void CGLIB$STATICHOOK1() { /* compiled code */ }
final void CGLIB$exit$0() { /* compiled code */ }
public final void exit() { /* compiled code */ }
final void CGLIB$login$1() { /* compiled code */ }
public final void login() { /* compiled code */ }
final void CGLIB$finalize$2() throws java.lang.Throwable { /* compiled code */ }
protected final void finalize() throws java.lang.Throwable { /* compiled code */ }
final boolean CGLIB$equals$3(java.lang.Object o) { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
final java.lang.String CGLIB$toString$4() { /* compiled code */ }
public final java.lang.String toString() { /* compiled code */ }
final int CGLIB$hashCode$5() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
final java.lang.Object CGLIB$clone$6() throws java.lang.CloneNotSupportedException { /* compiled code */ }
protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException { /* compiled code */ }
public static org.springframework.cglib.proxy.MethodProxy CGLIB$findMethodProxy(org.springframework.cglib.core.Signature signature) { /* compiled code */ }
public GamePlay$$EnhancerByCGLIB$$d2a7d2f3() { /* compiled code */ }
public static void CGLIB$SET_THREAD_CALLBACKS(org.springframework.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public static void CGLIB$SET_STATIC_CALLBACKS(org.springframework.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
private static final void CGLIB$BIND_CALLBACKS(java.lang.Object o) { /* compiled code */ }
public java.lang.Object newInstance(org.springframework.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public java.lang.Object newInstance(org.springframework.cglib.proxy.Callback callback) { /* compiled code */ }
public java.lang.Object newInstance(java.lang.Class[] classes, java.lang.Object[] objects, org.springframework.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public org.springframework.cglib.proxy.Callback getCallback(int i) { /* compiled code */ }
public void setCallback(int i, org.springframework.cglib.proxy.Callback callback) { /* compiled code */ }
public org.springframework.cglib.proxy.Callback[] getCallbacks() { /* compiled code */ }
public void setCallbacks(org.springframework.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
}
可以看到代理類(lèi)繼承了被代理類(lèi)满败,并重寫(xiě)了被代理類(lèi)的方法肤频,這個(gè)類(lèi)被裝入spring的bean容器中,供注入使用算墨。
下篇分析spring中的aop:
http://www.reibang.com/p/f7acdaec26f2