一、代理模式基本概念

1、模式說(shuō)明

proxy代理對(duì)象:(1)實(shí)現(xiàn)與具體的目標(biāo)對(duì)象一樣的接口,這樣就可以使用代理來(lái)代替具體的目標(biāo)對(duì)象(2)保存一個(gè)指向具體目標(biāo)對(duì)象的引用,可以在需要的時(shí)候調(diào)用具體的目標(biāo)對(duì)象,可以控制對(duì)具體目標(biāo)對(duì)象的訪問(wèn),并可能負(fù)責(zé)創(chuàng)建和刪除它
Subject目標(biāo)接口:定義代理和具體目標(biāo)對(duì)象的接口,這樣就可以在任何使用具體目標(biāo)對(duì)象的地方使用代理對(duì)象
RealSubject具體的目標(biāo)對(duì)象:真正實(shí)現(xiàn)目標(biāo)接口要求的功能。
2、代理運(yùn)行過(guò)程

3、代理功能
- 代理模式是通過(guò)創(chuàng)建一個(gè)代理對(duì)象,用這個(gè)代理對(duì)象去代表真實(shí)的對(duì)象,客戶端得到這個(gè)代理對(duì)象過(guò)后,對(duì)客戶端沒(méi)有什么影響,就跟得到了真實(shí)對(duì)象一樣來(lái)使用。
- 當(dāng)客戶端操作這個(gè)代理對(duì)象的時(shí)候,實(shí)際上功能最終還是會(huì)由真實(shí)的對(duì)象來(lái)完成,只不過(guò)是通過(guò)代理操作的,也就是客戶端操作代理,代理操作真正的對(duì)象。
代理其實(shí)就是中轉(zhuǎn)的意思,用代理對(duì)象去完成真實(shí)對(duì)象的動(dòng)作。但是因?yàn)槭侵修D(zhuǎn),可以利用代理完成很多對(duì)客戶端透明的東西,比如權(quán)限驗(yàn)證等。因此代理的作用可以歸納為:把一些共有的邏輯抽象到代理類中,由代理來(lái)完成,可以大大簡(jiǎn)化代碼的。
4、代理分類
- 靜態(tài)代理:(虛代理、保護(hù)代理、遠(yuǎn)程代理和智能指引等等)
- 動(dòng)態(tài)代理:jdk動(dòng)態(tài)代理、cglib動(dòng)態(tài)代理
二、靜態(tài)代理示例
1、創(chuàng)建需要代理的接口對(duì)象及其實(shí)現(xiàn)類
public interface Target {
String execute();
}
public class TargetImpl implements Target {
public String execute() {
System.err.println("TargetImpl execute!");
return "targetImpl";
}
}
2、創(chuàng)建代理對(duì)象
public class StaticProxy implements Target {
/**
* 需要被代理的目標(biāo)接口
*/
private Target target;
public StaticProxy(Target target) {
this.target = target;
}
public String execute() {
//代理類進(jìn)行代理方法操作(相當(dāng)于中轉(zhuǎn),但是同時(shí)可以添加很多的東西,比如日志、權(quán)限等等)
System.err.println("perProcess");
String result = this.target.execute();
System.out.println("postProcess");
return result;
}
}
3、測(cè)試
public class StaticProxyTest {
public static void main(String[] args) {
Target target=new TargetImpl();
StaticProxy proxy=new StaticProxy(target);
//代理類進(jìn)行代理處理
String execute = proxy.execute();
System.err.println(execute);
}
}
結(jié)果:
postProcess
perProcess
TargetImpl execute!
targetImpl
三、動(dòng)態(tài)代理
靜態(tài)代理具有一個(gè)明顯的缺點(diǎn)就是如果Subject接口發(fā)生變化,那么代理類和具體的目標(biāo)實(shí)現(xiàn)都要變化,不是很靈活。而動(dòng)態(tài)代理如其名,能動(dòng)態(tài)的適應(yīng)變化,應(yīng)用更加廣泛。
1、jdk動(dòng)態(tài)代理
- Java對(duì)代理模式提供了內(nèi)建的支持,在java.lang.reflect包下面,提供了一個(gè)Proxy的類和一個(gè)InvocationHandler的接口。
- Java的動(dòng)態(tài)代理目前只能代理接口,基本的實(shí)現(xiàn)是依靠Java的反射機(jī)制和動(dòng)態(tài)生成class的技術(shù),來(lái)動(dòng)態(tài)生成被代理的接口的實(shí)現(xiàn)對(duì)象。
- 使用jdk動(dòng)態(tài)代理的步驟:
(1)通過(guò)實(shí)現(xiàn)InvocationHandler接口來(lái)自定義自己的InvocationHandler;
(2)通過(guò)Proxy.getProxyClass獲得動(dòng)態(tài)代理類
(3)通過(guò)代理對(duì)象調(diào)用目標(biāo)方法
public class JdkProxyInvocation implements InvocationHandler {
private Object target;
public JdkProxyInvocation(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("========before==========");
Object result = method.invoke(target,args);
System.out.println("========after===========");
return result;
}
}
public class JdkProxy<T> {
/**
* 要被代理的對(duì)象
*/
private Class<T> target;
/**
* 具體處理邏輯的invoke
*/
private InvocationHandler invocationHandler;
public JdkProxy(Class<T> target, InvocationHandler invocationHandler) {
this.target = target;
this.invocationHandler = invocationHandler;
}
public T getProxyObject() {
return (T) Proxy.newProxyInstance(target.getClassLoader(),
target.getInterfaces() , invocationHandler);
}
}
public class JdkProxyTest {
public static void main(String[] args) {
Target target = new TargetImpl();
JdkProxyInvocation jdkProxyInvocation = new JdkProxyInvocation(target);
//獲取代理對(duì)象
Target proxy = (Target) new JdkProxy(target.getClass(), jdkProxyInvocation)
.getProxyObject();
proxy.execute();
}
}
如果想深入可以看這篇分析源碼的博客:深度剖析 JDK 動(dòng)態(tài)代理機(jī)制
2、cglib代理
CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢(shì)織入橫切邏輯。
public class CglibProxy implements MethodInterceptor {
//單例模式
private static CglibProxy instance = new CglibProxy();
public static CglibProxy getInstance(){
return instance;
}
/**
* 創(chuàng)建代理對(duì)象
* @param cls 要代理的類
* @param <T>
* @return
*/
public <T> T getProxy(Class<T> cls){
return (T) Enhancer.create(cls, this);
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(">>>>MethodInterceptor start...");
Object result = methodProxy.invokeSuper(obj,args);
System.out.println(">>>>MethodInterceptor ending...");
return result;
}
}
public class CglibTarget {
public String execute() {
String message = "-----------test------------";
System.out.println(message);
return message;
}
}
public class CglibTest {
public static void main(String[] args) {
CglibTarget proxy = CglibProxy.getInstance().getProxy(CglibTarget.class);
proxy.execute();
}
}