一膘流、簡(jiǎn)介
1.1 定義
給某一個(gè)對(duì)象提供一個(gè)代理第喳,并由代理對(duì)象控制對(duì)真實(shí)對(duì)象的訪問(wèn)进宝,代理模式是結(jié)構(gòu)型設(shè)計(jì)模式的一種
根據(jù)字節(jié)碼文件的創(chuàng)建時(shí)機(jī)來(lái)分類瞭亮,可以分為靜態(tài)代理和動(dòng)態(tài)代理
1.2 靜態(tài)代理
在程序運(yùn)行前就已經(jīng)存在代理類的字節(jié)碼文件痹换,代理類和被目標(biāo)類的關(guān)系在運(yùn)行前就確定了
1.3 動(dòng)態(tài)代理
代理類在程序運(yùn)行期間優(yōu)JVM根據(jù)反射等機(jī)制動(dòng)態(tài)生成泻帮,在程序運(yùn)行前并不存在代理類的字節(jié)碼文件
為什么需要?jiǎng)討B(tài)代理精置?
靜態(tài)代理實(shí)現(xiàn)簡(jiǎn)單,且能夠在不侵入原代碼的情況下實(shí)現(xiàn)目標(biāo)類的功能擴(kuò)展锣杂。但是當(dāng)場(chǎng)景稍微復(fù)雜的時(shí)候脂倦,靜態(tài)代理存在如下缺點(diǎn):
1、當(dāng)需要對(duì)多個(gè)類代理時(shí)元莫,由于代理類要實(shí)現(xiàn)和目標(biāo)類一致的接口赖阻,有兩種方式
(這里指的實(shí)現(xiàn)不同接口的目標(biāo)類,如果需要擴(kuò)展實(shí)現(xiàn)同一接口的目標(biāo)類可以選擇使用裝飾器模式)
- 只維護(hù)一個(gè)代理類柒竞,實(shí)現(xiàn)所有的目標(biāo)類接口政供,但是這樣會(huì)導(dǎo)致代理類過(guò)于龐大
- 維護(hù)多個(gè)代理類,每個(gè)目標(biāo)對(duì)象對(duì)應(yīng)一個(gè)代理類,但是這樣會(huì)導(dǎo)致代理類過(guò)多
2布隔、當(dāng)接口需要新增离陶,刪除,修改的時(shí)候衅檀,目標(biāo)類和代理類都要同時(shí)修改招刨,不易維護(hù)
動(dòng)態(tài)代理可以解決上述靜態(tài)代理的缺點(diǎn)
二、實(shí)現(xiàn)方式和原理
2.1 JDK動(dòng)態(tài)代理
該方式為通過(guò)實(shí)現(xiàn)接口的方式
JDK動(dòng)態(tài)代理主要設(shè)計(jì)兩個(gè)類:java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
2.1.1 實(shí)現(xiàn)示例
- 目標(biāo)類接口:
public interface TargetInterface {
/**
* 原始方法1
*
* @return String
*/
String doSomething();
/**
* 原始方法2
*
* @return int
*/
int printNum();
}
- 目標(biāo)類:
public class Target implements TargetInterface {
@Override
public String doSomething() {
System.out.println("doSomething");
return "doSomething";
}
@Override
public int printNum() {
System.out.println("printNum");
return 100;
}
}
- 代理類邏輯處理:(不是真正的代理類)
public class DynamicProxyHandler implements InvocationHandler {
/**
* 目標(biāo)對(duì)象
*/
private final Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do something before");
Object invoke = method.invoke(target, args);
System.out.println("do something after");
return invoke;
}
}
- 動(dòng)態(tài)代理對(duì)象生成:
mport java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1哀军、創(chuàng)建被代理的目標(biāo)對(duì)象
Target target = new Target();
//2沉眶、創(chuàng)建代理類處理器對(duì)象
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(target);
//3、創(chuàng)建代理類對(duì)象
//a.JDK會(huì)通過(guò)傳入的參數(shù)信息動(dòng)態(tài)地在內(nèi)存中創(chuàng)建和.class文件等同的字節(jié)碼
//b.然后會(huì)根據(jù)相應(yīng)的字節(jié)碼轉(zhuǎn)換成對(duì)應(yīng)的class
//c.最后創(chuàng)建代理類實(shí)例
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), dynamicProxyHandler);
System.out.println("doSomething() call: " + proxy.doSomething());
System.out.println("------------------------");
System.out.println("proxy.printNum() call: " + proxy.printNum());
}
}
- 輸出結(jié)果:
do something before
doSomething
do something after
doSomething() call: doSomething
------------------------
do something before
printNum
do something after
proxy.printNum() call: 100
2.1.2 原理說(shuō)明
- 具體步驟
- 通過(guò)實(shí)現(xiàn)
InvovationHandler
接口創(chuàng)建自己的調(diào)用處理器 - 通過(guò)為
Proxy
類指定ClassLoader對(duì)象和一組Interface來(lái)創(chuàng)建動(dòng)態(tài)代理類 - 通過(guò)反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)杉适,其唯一參數(shù)類型是
InvocationHandler
接口類型 - 通過(guò)構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類實(shí)例谎倔,調(diào)用處理器對(duì)象(
InvocationHandler
接口的實(shí)現(xiàn)類實(shí)例)作為參數(shù)傳入
Proxy
類分析
public class Proxy implements java.io.Serializable {
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 查找或者生成指定的代理類
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* 獲取參數(shù)為調(diào)用處理器接口的構(gòu)造函數(shù)對(duì)象
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
/*
* 如果Class的作用域?yàn)樗接校ㄟ^(guò)setAccessible設(shè)置可訪問(wèn)
*/
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
/*
* 創(chuàng)建代理類實(shí)例
*/
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
}
/**
* 生成代理類
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果實(shí)現(xiàn)指定接口的代理類存在于指定加載器中猿推,則直接返回緩存副本
// 否則通過(guò)ProxyClassFactory創(chuàng)建代理類
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory
類生成代理類
簡(jiǎn)單步驟就是先生成類的字節(jié)碼文件片习,再通過(guò)Proxy類的defineClass0本地方法生成字節(jié)碼文件。具體實(shí)現(xiàn)代碼可以查看Proxy類的靜態(tài)內(nèi)部類ProxyClassFactory源碼蹬叭。
- 字節(jié)碼文件
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
方法修改系統(tǒng)變量藕咏,可以保存生成的字節(jié)碼文件
字節(jié)碼文件:
package com.sun.proxy;
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 TargetInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String doSomething() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 int printNum() throws {
try {
return (Integer)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);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
- 代理類繼承Proxy類,實(shí)現(xiàn)目標(biāo)類接口(本例中對(duì)應(yīng)
TargetInterface
接口)秽五,重寫equals孽查、hashCode、toString的方法 - 類和方法都被public final 修飾坦喘,所以類和方法只能使用盲再,不能繼承和重寫
- 方法的實(shí)現(xiàn)最終會(huì)調(diào)用到代理調(diào)用處理器對(duì)象(本例中對(duì)應(yīng)
DynamicProxyHandler
類實(shí)例)的invoke方法
2.2 CGLIB動(dòng)態(tài)代理
CGLIB動(dòng)態(tài)代理是基于ASM機(jī)制實(shí)現(xiàn),通過(guò)生成業(yè)務(wù)類的子類作為代理類起宽。
具體使用介紹可參考如下文章