java中的代理是什么?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
成都創(chuàng)新互聯(lián)專(zhuān)注為客戶(hù)提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、武夷山網(wǎng)絡(luò)推廣、小程序設(shè)計(jì)、武夷山網(wǎng)絡(luò)營(yíng)銷(xiāo)、武夷山企業(yè)策劃、武夷山品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供武夷山建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com
代理是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問(wèn)方式,即通過(guò)代理對(duì)象訪問(wèn)目標(biāo)對(duì)象。可以不修改目標(biāo)對(duì)象,對(duì)目標(biāo)對(duì)象功能進(jìn)行拓展。
代理的作用:降低代碼的冗余。
代理模式的實(shí)現(xiàn)分為兩大類(lèi):靜態(tài)實(shí)現(xiàn)和動(dòng)態(tài)實(shí)現(xiàn),動(dòng)態(tài)實(shí)現(xiàn)根據(jù)實(shí)現(xiàn)的方式分為:jdk 動(dòng)態(tài)實(shí)現(xiàn),cglib動(dòng)態(tài)實(shí)現(xiàn)
Java的三種代理模式
想要實(shí)現(xiàn)以上的需求有三種方式,這一部分我們只看三種模式的代碼怎么寫(xiě),先不涉及實(shí)現(xiàn)原理的部分。
1、靜態(tài)代理
public interface ISinger { void sing(); } /** * 目標(biāo)對(duì)象實(shí)現(xiàn)了某一接口 */ public class Singer implements ISinger{ public void sing(){ System.out.println("唱一首歌"); } } /** * 代理對(duì)象和目標(biāo)對(duì)象實(shí)現(xiàn)相同的接口 */ public class SingerProxy implements ISinger{ // 接收目標(biāo)對(duì)象,以便調(diào)用sing方法 private ISinger target; public UserDaoProxy(ISinger target){ this.target=target; } // 對(duì)目標(biāo)對(duì)象的sing方法進(jìn)行功能擴(kuò)展 public void sing() { System.out.println("向觀眾問(wèn)好"); target.sing(); System.out.println("謝謝大家"); } }
測(cè)試
/** * 測(cè)試類(lèi) */ public class Test { public static void main(String[] args) { //目標(biāo)對(duì)象 ISinger target = new Singer(); //代理對(duì)象 ISinger proxy = new SingerProxy(target); //執(zhí)行的是代理的方法 proxy.sing(); } }
優(yōu)點(diǎn): 做到不修改目標(biāo)對(duì)象的功能前提下,對(duì)目標(biāo)功能擴(kuò)展
缺點(diǎn):這種實(shí)現(xiàn)方式很直觀也很簡(jiǎn)單,但其缺點(diǎn)是代理對(duì)象必須提前寫(xiě)出,如果接口層發(fā)生了變化,代理對(duì)象的代碼也要進(jìn)行維護(hù)。如果能在運(yùn)行時(shí)動(dòng)態(tài)地寫(xiě)出代理對(duì)象,不但減少了一大批代理類(lèi)的代碼,也少了不斷維護(hù)的煩惱,不過(guò)運(yùn)行時(shí)的效率必定受到影響。這種方式就是接下來(lái)的動(dòng)態(tài)代理。
2、JDK代理
跟靜態(tài)代理的前提一樣,依然是對(duì)Singer對(duì)象進(jìn)行擴(kuò)展
public interface ISinger { void sing(); } /** * 目標(biāo)對(duì)象實(shí)現(xiàn)了某一接口 */ public class Singer implements ISinger{ public void sing(){ System.out.println("唱一首歌"); } }
這回直接上測(cè)試,由于java底層封裝了實(shí)現(xiàn)細(xì)節(jié)(之后會(huì)詳細(xì)講),所以代碼非常簡(jiǎn)單,格式也基本上固定。
調(diào)用Proxy類(lèi)的靜態(tài)方法newProxyInstance即可,該方法會(huì)返回代理類(lèi)對(duì)象
static Object newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h )
接收的三個(gè)參數(shù)依次為:
● ClassLoader loader:指定當(dāng)前目標(biāo)對(duì)象使用類(lèi)加載器,寫(xiě)法固定
● Class>[] interfaces:目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類(lèi)型,寫(xiě)法固定
● InvocationHandler h:事件處理接口,需傳入一個(gè)實(shí)現(xiàn)類(lèi),一般直接使用匿名內(nèi)部類(lèi)
測(cè)試代碼
public class Test{ public static void main(String[] args) { Singer target = new Singer(); ISinger proxy = (ISinger) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("向觀眾問(wèn)好"); //執(zhí)行目標(biāo)對(duì)象方法 Object returnValue = method.invoke(target, args); System.out.println("謝謝大家"); return returnValue; } }); proxy.sing(); } }
優(yōu)點(diǎn):動(dòng)態(tài)實(shí)現(xiàn)了不改變目標(biāo)對(duì)象邏輯的擴(kuò)展
缺點(diǎn):可以看出靜態(tài)代理和JDK代理有一個(gè)共同的缺點(diǎn),就是目標(biāo)對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口,不然無(wú)法實(shí)現(xiàn)動(dòng)態(tài)代理。
3、Cglib代理
前提條件:
● 需要引入cglib的jar文件,由于Spring的核心包中已經(jīng)包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
● 目標(biāo)類(lèi)不能為final
● 目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法
/** * 目標(biāo)對(duì)象,沒(méi)有實(shí)現(xiàn)任何接口 */ public class Singer{ public void sing() { System.out.println("唱一首歌"); } }
/** * Cglib子類(lèi)代理工廠 */ public class ProxyFactory implements MethodInterceptor{ // 維護(hù)目標(biāo)對(duì)象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象 public Object getProxyInstance(){ //1.工具類(lèi) Enhancer en = new Enhancer(); //2.設(shè)置父類(lèi) en.setSuperclass(target.getClass()); //3.設(shè)置回調(diào)函數(shù) en.setCallback(this); //4.創(chuàng)建子類(lèi)(代理對(duì)象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("向觀眾問(wèn)好"); //執(zhí)行目標(biāo)對(duì)象的方法 Object returnValue = method.invoke(target, args); System.out.println("謝謝大家"); return returnValue; } }
這里的代碼也非常固定,只有標(biāo)黃部分是需要自己寫(xiě)出
測(cè)試
/** * 測(cè)試類(lèi) */ public class Test{ public static void main(String[] args){ //目標(biāo)對(duì)象 Singer target = new Singer(); //代理對(duì)象 Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance(); //執(zhí)行代理對(duì)象的方法 proxy.sing(); } }
優(yōu)點(diǎn):動(dòng)態(tài)實(shí)現(xiàn)了不改變目標(biāo)對(duì)象邏輯的擴(kuò)展
缺點(diǎn):目標(biāo)必須實(shí)現(xiàn)接口,不然無(wú)法實(shí)現(xiàn)動(dòng)態(tài)代理
總結(jié):三種代理模式各有優(yōu)缺點(diǎn)和相應(yīng)的適用范圍,主要看目標(biāo)對(duì)象是否實(shí)現(xiàn)了接口。以Spring框架所選擇的代理模式舉例
在Spring的AOP編程中:
如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,用JDK代理
如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,用Cglib代理
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。