代理模式在java中隨處可見,其他編程語言也一樣,它的作用就是用來解耦的。代理模式又分為靜態(tài)代理和動態(tài)代理。
先從簡單的開始,來一段靜態(tài)代理的示例代碼:
/**
* 接口
*/
interface Person {
void study();
}
/**
* 被代理類
*/
class Student implements Person {
@Override
public void study() {
System.out.print("study");
}
}
/**
* 針對Student創(chuàng)建一個代理類
*/
class StudentProxy implements Person {
/**
* 需要被代理類作為其屬性
*/
private Student student;
/**
* 通過構(gòu)造函數(shù)將被代理類設(shè)置進來
*
* @param student
*/
public StudentProxy(Student student) {
this.student = student;
}
/**
* 同樣是study,代理類在原有的功能上做了增強
*/
@Override
public void study() {
//前置增強
System.out.print("開始學(xué)習(xí)");
//調(diào)用被代理實例的study方法
student.study();
//后置增強
System.out.print("學(xué)習(xí)結(jié)束");
}
}
測試代碼:
public static void main(String[] args) {
Person person = new Student();
person.study();
//輸出結(jié)果:study
person = new StudentProxy(new Student());
person.study();
//輸出結(jié)果:開始學(xué)習(xí)study學(xué)習(xí)結(jié)束
}
但是,靜態(tài)代理會帶來的一個問題是,如果需要代理的類特別多,我們就需要有同等數(shù)量的代理類,這樣做顯然是不行的。在了解了類加載原理的前提下,我們可以動態(tài)生成代理類。
JDK動態(tài)代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class ProxyInvocationHandler implements InvocationHandler {
/**
* 被代理對象
*/
private Object object;
/**
* 利用構(gòu)造函數(shù)設(shè)置被代理類屬性
*
* @param object
*/
public ProxyInvocationHandler(Object object) {
this.object = object;
}
/**
* 創(chuàng)建一個代理對象
*
* @return
*/
public Object newProxyInstance() {
/**
* 獲取被代理類的接口
*/
Class<?>[] classes = this.object.getClass().getInterfaces();
/**
* 創(chuàng)建代理對象
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, this);
}
/**
* 調(diào)用代理對象的方法
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("前置處理");
/**
* 執(zhí)行被代理對象方法
*/
Object result = method.invoke(object);
System.out.print("后置處理");
return result;
}
}
測試代碼:
public static void main(String[] args) {
//創(chuàng)建一個InvocationHandler,并設(shè)置被代理對象
ProxyInvocationHandler handler = new ProxyInvocationHandler(new Student());
//創(chuàng)建代理對象
Person person = (Person) handler.newProxyInstance();
person.study();
//輸出結(jié)果:前置處理study后置處理
}
ProxyInvocationHandler針對于任何有接口的對象都可以創(chuàng)建對應(yīng)的代理對象,這樣的話,相對于靜態(tài)代理的方式,我們就減少了很多工作啦。
但是,InvocationHandler到底是怎么做到可以動態(tài)創(chuàng)建代理對象的呢?
1.其實我們可以結(jié)合靜態(tài)代理的原理,靜態(tài)代理的類是手工編寫的,那么我們是否可以讓代碼自動生成對應(yīng)的代理類呢?顯然是可以的。
2.我們?nèi)绻詣由闪舜眍悾覀冊趺醋孞VM知道它的存在呢?答案就在動態(tài)代理的代碼中:ClassLoader
/**
* 創(chuàng)建一個代理對象
*
* @return
*/
public Object newProxyInstance() {
/**
* 獲取被代理類的接口
*/
Class<?>[] classes = this.object.getClass().getInterfaces();
/**
* 創(chuàng)建代理對象
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, this);
}
我們把上面這段代碼拿出來看一下:
1.首先拿到被代理對象的接口。舉個例子:如果這個被代理對象是Student,那么它的接口就是Person。
2.Proxy.newProxyInstance()里面有三個參數(shù),第一個是ClassLoader,第二個是Class<?>[],第三個是InvocationHandler。
那么我大膽假設(shè)一下:
1.利用字符串拼接的方式創(chuàng)建一個代理類實現(xiàn)指定的接口,并且把InvocationHandler對象作為它的屬性。
2.利用ClassLoader把創(chuàng)建出來的代理類加載進JVM,最后利用反射創(chuàng)建一個代理類實例返回
按照上述假設(shè),只要調(diào)用代理對象實現(xiàn)的方法,就將這個方法的調(diào)用委托給InvocationHandler對象的invoke方法,這樣的話,就能實現(xiàn)增強處理。
為了驗證我的假設(shè),我把生成的代理類文件給出來:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Person {
/**
* equals方法
*/
private static Method m1;
/**
* Person的study方法
*/
private static Method m3;
/**
* toString方法
*/
private static Method m2;
/**
* hashCode方法
*/
private static Method m0;
/**
* 構(gòu)造函數(shù),用于設(shè)置InvocationHandler
*/
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
/**
* 重寫equals方法
*/
public final boolean equals(Object var1) throws {
try {
/**
* 委托給InvocationHandler處理
*/
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
/**
* 實現(xiàn)study
*/
public final void study() throws {
try {
/**
* 委托給InvocationHandler處理,這樣我們就可以做前后增強
*/
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
/**
* 重寫toString()
*/
public final String toString() throws {
try {
/**
* 委托給InvocationHandler處理
*/
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
/**
* 重寫hashCode
*/
public final int hashCode() throws {
try {
/**
* 委托給InvocationHandler處理
*/
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
/**
* 獲取所有可以代理的方法
*/
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("Person").getMethod("study");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
到這里,小伙伴應(yīng)該恍然大悟,完全就是靜態(tài)代理嘛,只不過代碼不再是手工編寫,而是代碼自動創(chuàng)建的,并且所有方法啥也沒做,全部交給了InvocationHandler來處理。
JDK動態(tài)代理有一點限制,就是一定要有接口,如果沒有接口怎么辦,難道我們就不能創(chuàng)建代理對象了?接下來我們來看另一種創(chuàng)建代理的方式:
CGLIB動態(tài)代理
因為CGLIB不是JDK原生的,所以我們得引一個jar包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
class ProxyMethodInterceptor implements MethodInterceptor {
/**
* 被代理對象
*/
private Object object;
/**
* 利用構(gòu)造函數(shù)設(shè)置被代理對象
*
* @param object
*/
public ProxyMethodInterceptor(Object object) {
this.object = object;
}
/**
* 創(chuàng)建代理對象
*
* @return
*/
public Object newProxyInstance() {
/**
* 創(chuàng)建Enhancer實例
*/
Enhancer enhancer = new Enhancer();
/**
* 設(shè)置被代理類
*/
enhancer.setSuperclass(this.object.getClass());
/**
* 設(shè)置回調(diào)
*/
enhancer.setCallback(this);
/**
* 創(chuàng)建代理
*/
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.print("前置通知");
/**
* 調(diào)用被代理對象方法
*/
Object result = methodProxy.invokeSuper(o, objects);
System.out.print("后置通知");
return result;
}
}
我們按照慣例,再來一次猜想:
1.既然接口是通過implements實現(xiàn)的代理,那沒有接口是不是可以通過extends實現(xiàn)代理呢?貌似是沒有問題的!
2.那為什么這次創(chuàng)建代理的時候沒有ClassLoader?其實在Enhancer里面還是通過getClassLoader()拿到的ClassLoader,原理不變
同樣為了證明咱們的猜想,我把CGLIB生成的類文件貼上來:
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 代理類,繼承了Sudent
*/
public class Student$$EnhancerByCGLIB$$6f952e1b extends Student implements Factory {
/**
* 一開始是false,標(biāo)記CGLIB$CALLBACK_0是否初始化
*/
private boolean CGLIB$BOUND;
/**
* 暫時不討論
*/
public static Object CGLIB$FACTORY_DATA;
/**
* 用來存放回調(diào),和線程綁定
*/
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
/**
* 用來存放回調(diào),用數(shù)組存放
*/
private static final Callback[] CGLIB$STATIC_CALLBACKS;
/**
* 回調(diào)
*/
private MethodInterceptor CGLIB$CALLBACK_0;
/**
* 暫不討論
*/
private static Object CGLIB$CALLBACK_FILTER;
/**
* study方法
*/
private static final Method CGLIB$study$0$Method;
/**
* study代理方法
*/
private static final MethodProxy CGLIB$study$0$Proxy;
/**
* 空參數(shù)
*/
private static final Object[] CGLIB$emptyArgs;
/**
* equals方法
*/
private static final Method CGLIB$equals$1$Method;
/**
* equals代理方法
*/
private static final MethodProxy CGLIB$equals$1$Proxy;
/**
* toString方法
*/
private static final Method CGLIB$toString$2$Method;
/**
* toString代理方法
*/
private static final MethodProxy CGLIB$toString$2$Proxy;
/**
* hashCode方法
*/
private static final Method CGLIB$hashCode$3$Method;
/**
* hashCode代理方法
*/
private static final MethodProxy CGLIB$hashCode$3$Proxy;
/**
* clone方法
*/
private static final Method CGLIB$clone$4$Method;
/**
* clone代理方法
*/
private static final MethodProxy CGLIB$clone$4$Proxy;
/**
* 初始化調(diào)用
*/
static void CGLIB$STATICHOOK1() {
/**
* 創(chuàng)建ThreadLocal實例
*/
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
/**
* 空參數(shù)
*/
CGLIB$emptyArgs = new Object[0];
/**
* 拿到代理類自己的Class實例
*/
Class var0 = Class.forName("Student$$EnhancerByCGLIB$$6f952e1b");
/**
* 被代理類class
*/
Class var1;
/**
* 通過反射的方式拿到Object類的equals,toString,hashCode,clone方法
*/
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
/**
* 把equals方法賦值給CGLIB$equals$1$Method
*/
CGLIB$equals$1$Method = var10000[0];
/**
* 創(chuàng)建equals方法的代理方法
*/
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
/**
* 把toString方法賦值給CGLIB$toString$2$Method
*/
CGLIB$toString$2$Method = var10000[1];
/**
* 創(chuàng)建toString方法的代理方法
*/
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
/**
* 把hashCode方法賦值給CGLIB$hashCode$3$Method
*/
CGLIB$hashCode$3$Method = var10000[2];
/**
* 創(chuàng)建hashCode方法的代理方法
*/
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
/**
* 把clone方法賦值給CGLIB$clone$4$Method
*/
CGLIB$clone$4$Method = var10000[3];
/**
* 創(chuàng)建clone方法的代理方法
*/
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
/**
* 被代理類的study方法
*/
CGLIB$study$0$Method = ReflectUtils.findMethods(new String[]{"study", "()V"}, (var1 = Class.forName("Student")).getDeclaredMethods())[0];
/**
* 創(chuàng)建代理類的study方法
*/
CGLIB$study$0$Proxy = MethodProxy.create(var1, var0, "()V", "study", "CGLIB$study$0");
}
/**
* 調(diào)用父類(被代理類)的study
*/
final void CGLIB$study$0() {
super.study();
}
/**
* 重寫父類的study(也就是實現(xiàn)代理功能)
*/
public final void study() {
/**
* 拿到MethodInterceptor
*/
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
//設(shè)置回調(diào)
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//調(diào)用MethodInterceptor.intercept(這是重點),回到我們自己實現(xiàn)的MethodInterceptor中
var10000.intercept(this, CGLIB$study$0$Method, CGLIB$emptyArgs, CGLIB$study$0$Proxy);
} else {
//如果沒有回調(diào),就直接執(zhí)行父類的study
super.study();
}
}
/**
* 調(diào)用父類(被代理類)的equals方法
*
* @param var1
* @return
*/
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
/**
* 重寫父類的equals方法(也就是實現(xiàn)代理功能)
*
* @param var1
* @return
*/
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean) var2;
} else {
return super.equals(var1);
}
}
/**
* 調(diào)用父類(被代理類)的toString方法
*
* @return
*/
final String CGLIB$toString$2() {
return super.toString();
}
/**
* 重寫父類的toString方法(也就是實現(xiàn)代理功能)
*
* @return
*/
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String) var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
/**
* 調(diào)用父類(被代理類)的hashCode方法
*
* @return
*/
final int CGLIB$hashCode$3() {
return super.hashCode();
}
/**
* 重寫父類的hashCode方法(也就是實現(xiàn)代理功能)
*
* @return
*/
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number) var1).intValue();
} else {
return super.hashCode();
}
}
/**
* 調(diào)用父類(被代理類)的clone方法
*
* @return
* @throws CloneNotSupportedException
*/
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
/**
* 重寫父類的clone方法(也就是實現(xiàn)代理功能)
*
* @return
* @throws CloneNotSupportedException
*/
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
/**
* 獲取一個代理方法
*
* @param var0
* @return
*/
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch (var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1876544780:
if (var10000.equals("study()V")) {
return CGLIB$study$0$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
/**
* 設(shè)置回調(diào)
*/
public Student$$EnhancerByCGLIB$$6f952e1b() {
CGLIB$BIND_CALLBACKS(this);
}
/**
* 把回調(diào)放進ThreadLocal中
*
* @param var0
*/
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
/**
* 設(shè)置回調(diào)
* @param var0
*/
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
/**
* 初始化CGLIB$CALLBACK_0(設(shè)置回調(diào))
*
* @param var0
*/
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
Student$$EnhancerByCGLIB$$6f952e1b var1 = (Student$$EnhancerByCGLIB$$6f952e1b) var0;
/**
* 一開始CGLIB$BOUND就是false
*/
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
/**
* 給CGLIB$CALLBACK_0賦值
*/
var1.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) var10000)[0];
}
}
/**
* 創(chuàng)建代理對象
* @param var1
* @return
*/
public Object newInstance(Callback[] var1) {
/**
* 把回調(diào)放進ThreadLocal
*/
CGLIB$SET_THREAD_CALLBACKS(var1);
/**
* 創(chuàng)建一個代理對象
*/
Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b();
/**
* 清除ThreadLocal中的回調(diào)
*/
CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);
/**
* 返回代理對象
*/
return var10000;
}
/**
* 創(chuàng)建代理對象(同上)
* @param var1
* @return
*/
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b();
CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);
return var10000;
}
/**
* 創(chuàng)建代理對象(同上)
* @param var1
* @param var2
* @param var3
* @return
*/
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
Student$$EnhancerByCGLIB$$6f952e1b var10000 = new Student$$EnhancerByCGLIB$$6f952e1b;
switch (var1.length) {
case 0:
var10000.<init> ();
CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
/**
* 獲取回調(diào)
* @param var1
* @return
*/
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch (var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
/**
* 設(shè)置回調(diào)
* @param var1
* @param var2
*/
public void setCallback(int var1, Callback var2) {
switch (var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor) var2;
default:
}
}
/**
* 創(chuàng)建回調(diào)數(shù)組
* @return
*/
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
/**
* 設(shè)置回調(diào)數(shù)組
* @param var1
*/
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor) var1[0];
}
/**
* 首先執(zhí)行CGLIB$STATICHOOK1方法
*/
static {
CGLIB$STATICHOOK1();
}
}
根據(jù)上述的代碼,我們可以肯定我們的猜想是正確的。不過CGLIB是以直接生成字節(jié)碼的方式創(chuàng)建的代理類。
所謂的動態(tài)代理其實思想和靜態(tài)代理一樣,只不過我們將苦力活轉(zhuǎn)變成了腦力活,使我們需要的代理對象可以自動生成。
注意:因為final修飾的方法是不可以被重寫的,也就意味著final修飾的方法不能夠被代理
以上就是我對代理模式的簡單剖析,感興趣的小伙伴也可以根據(jù)原理自己實現(xiàn)一個創(chuàng)建代理對象的工具類。