定制品牌湘潭seo快速排名
1.代理模式
定義:代理模式就是代替對(duì)象具備真實(shí)對(duì)象的功能,并代替真實(shí)對(duì)象完成相應(yīng)的操作并且在不改變真實(shí)對(duì)象源代碼的情況下擴(kuò)展其功能,在某些情況下,?個(gè)對(duì)象不適合或者不能直接引?另?個(gè)對(duì)象,?代理對(duì)象可以在客戶端和?標(biāo)對(duì)象之間起到中介的作?
使用代理模式可以降低系統(tǒng)的耦合性,擴(kuò)展性好,并且可以起到保護(hù)目標(biāo)對(duì)象的作用
例如:我們平時(shí)租房的過(guò)程,租房中介就相當(dāng)于代理類(lèi)
代理模式分為靜態(tài)代理和動(dòng)態(tài)代理
2.靜態(tài)代理
靜態(tài)代理實(shí)現(xiàn)步驟:
- 定義?個(gè)接?及其實(shí)現(xiàn)類(lèi)(目標(biāo)類(lèi));
- 創(chuàng)建?個(gè)代理類(lèi)同樣實(shí)現(xiàn)這個(gè)接?(繼承同一個(gè)接口的原因就是,代理類(lèi)需要擁有和目標(biāo)類(lèi)同樣的方法這樣才能代理)
- 將?標(biāo)對(duì)象注?進(jìn)代理類(lèi),然后在代理類(lèi)的對(duì)應(yīng)?法調(diào)??標(biāo)類(lèi)中的對(duì)應(yīng)?法。
public interface IRentHouse {void rent();
}
public class RentHouse implements IRentHouse{@Overridepublic void rent() {System.out.println("租戶租房子");}
}
public class IntermediaryProxy implements IRentHouse{private IRentHouse iRentHouse;public IntermediaryProxy(IRentHouse iRentHouse) {this.iRentHouse = iRentHouse;}@Overridepublic void rent() {System.out.println("交中介費(fèi)");iRentHouse.rent();System.out.println("租房子后中介負(fù)責(zé)維護(hù)管理");}
}
/*** 測(cè)試類(lèi)*/
public class Test {public static void main(String[] args) {// 定義租房IRentHouse iRentHouse = new RentHouse();// 定義中介IRentHouse proxy = new IntermediaryProxy(iRentHouse);// 租房proxy.rent();}
}
運(yùn)行結(jié)果如下:
靜態(tài)代理有很多缺點(diǎn),實(shí)際應(yīng)用場(chǎng)景非常少,幾乎不用
對(duì)目標(biāo)對(duì)象的每個(gè)方法的增強(qiáng)都是手動(dòng)完成的,非常不靈活(比如接口中一旦新增方法,目標(biāo)對(duì)象和代理對(duì)象都要修改),且麻煩(需要對(duì)每個(gè)目標(biāo)類(lèi)都單獨(dú)寫(xiě)一個(gè)代理類(lèi))
3.動(dòng)態(tài)代理
相比于靜態(tài)代理來(lái)說(shuō),動(dòng)態(tài)代理更加靈活,不需要針對(duì)每個(gè)目標(biāo)類(lèi)都單獨(dú)創(chuàng)建一個(gè)代理類(lèi),也不需要我們必須實(shí)現(xiàn)接口
動(dòng)態(tài)代理允許使用一種方法的單個(gè)類(lèi)(代理類(lèi)),為具有任意數(shù)量方法的任意類(lèi)(目標(biāo)類(lèi))的多個(gè)方法提供服務(wù),看到這句話,是不是聯(lián)想到動(dòng)態(tài)代理的實(shí)現(xiàn)與Java反射機(jī)制密不可分
Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法,對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)屬性和方法,這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱之為Java語(yǔ)言的反射機(jī)制
從 JVM ?度來(lái)說(shuō),動(dòng)態(tài)代理是在運(yùn)?時(shí)動(dòng)態(tài)?成類(lèi)字節(jié)碼,并加載到 JVM 中
的。說(shuō)到動(dòng)態(tài)代理,不得不提的是Spring AOP,它的實(shí)現(xiàn)依賴了動(dòng)態(tài)代理
代理類(lèi)的兩個(gè)作用
1.添加增強(qiáng)方法,2.調(diào)用目標(biāo)類(lèi)
1.jdk動(dòng)態(tài)代理(接口代理)
在 Java 動(dòng)態(tài)代理機(jī)制中java.long.reflect包中的 InvocationHandler 接?和 Proxy 類(lèi)是核?
實(shí)際上就是在內(nèi)存中生產(chǎn)一個(gè)對(duì)象,該對(duì)象實(shí)現(xiàn)了指定的目標(biāo)對(duì)象的所有接口,代理對(duì)象和目標(biāo)對(duì)象是兄弟關(guān)系,
jdk自帶動(dòng)態(tài)代理技術(shù),需要使用一個(gè)靜態(tài)方法來(lái)創(chuàng)建代理對(duì)象,他需要目標(biāo)對(duì)象必須實(shí)現(xiàn)接口,生產(chǎn)的代理對(duì)象和目標(biāo)對(duì)象都實(shí)現(xiàn)同一個(gè)接口
JDK 動(dòng)態(tài)代理類(lèi)使?步驟:
- 定義?個(gè)接?及其實(shí)現(xiàn)類(lèi);
- ?定義 InvocationHandler 并重寫(xiě)invoke?法,在 invoke ?法中我們會(huì)調(diào)? 原??法(被代理類(lèi)的?法)并?定義?些處理邏輯;
- 通過(guò) Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) ?法創(chuàng)建代理對(duì)象;
1.定義JDK動(dòng)態(tài)代理類(lèi)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;// JDK 動(dòng)態(tài)代理類(lèi)
public class JDKInvocationHandler implements InvocationHandler {//?標(biāo)對(duì)象即就是被代理對(duì)象private Object target;public JDKInvocationHandler(Object target) {this.target = target;}/**** @param proxy 代理對(duì)象* @param method 代理方法* @param args 參數(shù)** @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 1234就是一些增強(qiáng)方法//1.安全檢查System.out.println("安全檢查");//2.記錄?志System.out.println("記錄?志");//3.時(shí)間統(tǒng)計(jì)開(kāi)始System.out.println("記錄開(kāi)始時(shí)間");//通過(guò)反射調(diào)?被代理類(lèi)的?法Object retVal = method.invoke(target, args);//4.時(shí)間統(tǒng)計(jì)結(jié)束System.out.println("記錄結(jié)束時(shí)間");return retVal;}
}
2.創(chuàng)建?個(gè)代理對(duì)象并使用
public class Main {public static void main(String[] args) {// 代理對(duì)象PayService target= new AliPayService();// 靜態(tài)的是已經(jīng)寫(xiě)好了的// 動(dòng)態(tài)的創(chuàng)建?個(gè)代理類(lèi):通過(guò)被代理類(lèi)、被代理實(shí)現(xiàn)的接?、?法調(diào)?處理器來(lái)創(chuàng)建PayService proxy = (PayService) Proxy.newProxyInstance(// 通過(guò)目標(biāo)類(lèi)的getClassLoadertarget.getClass().getClassLoader(),// 被代理類(lèi)實(shí)現(xiàn)的一些接口new Class[]{PayService.class},// 實(shí)現(xiàn)了InvocationHandler接口的對(duì)象new JDKInvocationHandler(target));proxy.pay();}}
Proxy 類(lèi)中使?頻率最?的?法是:newProxyInstance() ,這個(gè)?法主要?來(lái)?成?個(gè)代理對(duì)象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{....}
這個(gè)?法?共有 3 個(gè)參數(shù):
- loader :類(lèi)加載器,?于加載代理對(duì)象。
- interfaces : 被代理類(lèi)實(shí)現(xiàn)的?些接?;
- h : 實(shí)現(xiàn)了 InvocationHandler 接?的對(duì)象;
運(yùn)行main方法
JDK 動(dòng)態(tài)代理有?個(gè)最致命的問(wèn)題是其只能代理實(shí)現(xiàn)了接?的類(lèi),為了解決這個(gè)問(wèn)題,我們可以? CGLIB 動(dòng)態(tài)代理機(jī)制來(lái)避免
CGLIB(Code GenerationLibrary)是?個(gè)基于ASM的字節(jié)碼?成庫(kù),它允許我們?cè)谶\(yùn)?時(shí)對(duì)字節(jié)碼進(jìn)?修改和動(dòng)態(tài)?成。CGLIB通過(guò)繼承?式實(shí)現(xiàn)代理。很多知名的開(kāi)源框架都使?到了CGLIB, 例如 Spring 中的 AOP 模塊中:如果?標(biāo)對(duì)象實(shí)現(xiàn)了接?,則默認(rèn)采?JDK 動(dòng)態(tài)代理,否則采? CGLIB 動(dòng)態(tài)代理。
在 CGLIB 動(dòng)態(tài)代理機(jī)制中 MethodInterceptor 接?和 Enhancer 類(lèi)是核?
2.CGLIB 動(dòng)態(tài)代理類(lèi)使?步驟
- 定義?個(gè)類(lèi);
- ?定義 MethodInterceptor 并重寫(xiě) intercept ?法,intercept ?于攔截增強(qiáng)
被代理類(lèi)的?法,和 JDK 動(dòng)態(tài)代理中的 invoke ?法類(lèi)似; - 通過(guò) Enhancer 類(lèi)的 create()創(chuàng)建代理類(lèi)
1.添加依賴
和JDK 動(dòng)態(tài)代理不同, CGLIB(Code Generation Library) 實(shí)際是屬于?個(gè)開(kāi)源項(xiàng)?,如果你要使?它的話,需要?動(dòng)添加相關(guān)依賴
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
2.?定義 MethodInterceptor(?法攔截器)
public class CGLIBInterceptor implements MethodInterceptor {//被代理對(duì)象private Object target;public CGLIBInterceptor(Object target){this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] args, Method
Proxy methodProxy) throws Throwable {//1.安全檢查System.out.println("安全檢查");//2.記錄?志System.out.println("記錄?志");//3.時(shí)間統(tǒng)計(jì)開(kāi)始System.out.println("記錄開(kāi)始時(shí)間");//通過(guò)cglib的代理?法調(diào)?Object retVal = methodProxy.invoke(target, args);//4.時(shí)間統(tǒng)計(jì)結(jié)束System.out.println("記錄結(jié)束時(shí)間");return retVal;}
}
3.創(chuàng)建代理類(lèi), 并使?
public static void main(String[] args) {PayService target= new AliPayService();PayService proxy= (PayService) Enhancer.create(target.getClass(),ne
w CGLIBInterceptor(target));proxy.pay();}
你需要?定義 MethodInterceptor 并重寫(xiě) intercept ?法,intercept ?于攔截增強(qiáng)被代理類(lèi)的?法
public interface MethodInterceptor
extends Callback{// 攔截被代理類(lèi)中的?法public Object intercept(Object obj, java.lang.reflect.Method method, Ob
ject[] args,MethodProxy proxy) throws Throwable;
}
- obj : 被代理的對(duì)象(需要增強(qiáng)的對(duì)象)
- method : 被攔截的?法(需要增強(qiáng)的?法)
- args : ?法?參
- proxy : ?于調(diào)?原始?法
3.JDK 動(dòng)態(tài)代理和 CGLIB 動(dòng)態(tài)代理對(duì)?:
- JDK 動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接?的類(lèi)或者直接代理接?,? CGLIB 可以代理未實(shí)現(xiàn)任何接?的類(lèi)
- CGLIB動(dòng)態(tài)代理是通過(guò)?成?個(gè)被代理類(lèi)的?類(lèi)來(lái)攔截被代理類(lèi)的?法調(diào)?,因此不能代理聲明為 final
性能: ?部分情況都是 JDK 動(dòng)態(tài)代理更優(yōu)秀,隨著 JDK 版本的升級(jí),這個(gè)優(yōu)勢(shì)更加明顯
Spring代理選擇
- proxyTargetClass 為false, ?標(biāo)實(shí)現(xiàn)了接?, ?jdk代理
- proxyTargetClass 為false, ?標(biāo)未實(shí)現(xiàn)接?, ?cglib代理
- proxyTargetClass 為true, ?cglib代理
下篇見(jiàn)~