java的三種代理

代理

靜態(tài)代理

  1. 編寫需要目標(biāo)對象實現(xiàn)的接口
/**
 * 接口
 */
public interface Action {

    /**
     * dosomething
     */
    void doSomething();
}
  1. 編寫目標(biāo)類恩掷,實現(xiàn)接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject implements Action {

    @Override
    public void doSomething() {
        System.out.println(this.getClass().getName()+"dosomething....");
    }
}
  1. 編寫靜態(tài)代理類寞酿,也需要實現(xiàn)該接口
/**
 * 代理類
 *
 * @author earthchen
 * @date 2018/8/10
 **/
public class Proxy implements Action {

    private Action realObject;

    public Proxy(Action realObject) {
        this.realObject = realObject;
    }

    @Override
    public void doSomething() {
        System.out.println("proxy do");
        realObject.doSomething();
    }
}

需要維護(hù)一個接口的對象

  1. 編寫main方法進(jìn)行測試
public class Main {

    public static void main(String[] args) {
        Action action = new RealObject();
        Proxy proxy = new Proxy(action);
        proxy.doSomething();
    }
}

優(yōu)缺點(diǎn)

這種代理方式需要代理對象和目標(biāo)對象實現(xiàn)一樣的接口。

  1. 優(yōu)點(diǎn):可以在不修改目標(biāo)對象的前提下擴(kuò)展目標(biāo)對象的功能雌澄。

  2. 缺點(diǎn):

  • 冗余伊者。由于代理對象要實現(xiàn)與目標(biāo)對象一致的接口,會產(chǎn)生過多的代理類胁赢。
  • 不易維護(hù)企蹭。一旦接口增加方法,目標(biāo)對象與代理對象都要進(jìn)行修改智末。

jdk動態(tài)代理

  1. 和靜態(tài)代理一樣谅摄,編寫一個接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public interface Action {

    void doSomeThing();

}
  1. 編寫多個目標(biāo)類,實現(xiàn)接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject1 implements Action {

    @Override
    public void doSomeThing() {
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject2 implements Action {

    @Override
    public void doSomeThing() {
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}
  1. 編寫動態(tài)代理類系馆,
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class DynamicProxyHandler implements InvocationHandler {

    private Action testAction;

    public DynamicProxyHandler(Action testAction) {
        this.testAction = testAction;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理擴(kuò)展邏輯
        System.out.println("proxy do");

        return method.invoke(testAction, args);
    }
}
  1. 編寫main方法進(jìn)行測試
public class Main {

    public static void main(String[] args) {
        RealObject1 realObject1 = new RealObject1();
        Action proxy1 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Action.class}, new DynamicProxyHandler(realObject1));
        proxy1.doSomeThing();


        RealObject2 realObject2 = new RealObject2();
        Action proxy2 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Action.class}, new DynamicProxyHandler(realObject2));
        proxy2.doSomeThing();
    }
}

靜態(tài)代理與動態(tài)代理的區(qū)別

  • 靜態(tài)代理在編譯時就已經(jīng)實現(xiàn)送漠,編譯完成后代理類是一個實際的class文件
  • 動態(tài)代理是在運(yùn)行時動態(tài)生成的,即編譯完成后沒有實際的class文件由蘑,而是在運(yùn)行時動態(tài)生成類字節(jié)碼闽寡,并加載到JVM中

特點(diǎn):

動態(tài)代理對象不需要實現(xiàn)接口,但是要求目標(biāo)對象必須實現(xiàn)接口尼酿,否則不能使用動態(tài)代理爷狈。

cglib代理

  1. 在pom.xml中引入cglib的依賴
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>
  1. 直接編寫需要代理的目標(biāo)類
public class RealObject {

    public void doSomeThing(){
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}
  1. 編寫cglib代理類
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class CglibProxy implements MethodInterceptor {

    private Object target;

    public CglibProxy(Object object) {
        this.target = object;
    }

    /**
     * 為目標(biāo)對象生成代理對象
     *
     * @return
     */
    public Object getProxyInstance() {
        //工具類
        Enhancer en = new Enhancer();
        //設(shè)置父類
        en.setSuperclass(target.getClass());
        //設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //創(chuàng)建子類對象代理
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before do someThing.....");
        // 執(zhí)行目標(biāo)對象的方法
        Object returnValue = method.invoke(target, objects);
        System.out.println("after do someThing....");
        return returnValue;
    }
}

cglib與動態(tài)代理的區(qū)別

  • 使用動態(tài)代理的對象必須實現(xiàn)一個或多個接口
  • 使用cglib代理的對象則無需實現(xiàn)接口,達(dá)到代理類無侵入裳擎。

cglib特點(diǎn)

  • JDK的動態(tài)代理有一個限制涎永,就是使用動態(tài)代理的對象必須實現(xiàn)一個或多個接口。
    如果想代理沒有實現(xiàn)接口的類鹿响,就可以使用CGLIB實現(xiàn)
  • CGLIB是一個強(qiáng)大的高性能的代碼生成包羡微,它可以在運(yùn)行期擴(kuò)展Java類與實現(xiàn)Java接口。它廣泛的被許多AOP的框架使用惶我,例如Spring AOP和dynaop妈倔,為他們提供方法的interception(攔截)
  • CGLIB包的底層是通過使用一個小而快的字節(jié)碼處理框架ASM,來轉(zhuǎn)換字節(jié)碼并生成新的類绸贡。不鼓勵直接使用ASM盯蝴,因為它需要你對JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉

總結(jié)

  1. 靜態(tài)代理實現(xiàn)較簡單毅哗,只要代理對象對目標(biāo)對象進(jìn)行包裝,即可實現(xiàn)增強(qiáng)功能结洼,但靜態(tài)代理只能為一個目標(biāo)對象服務(wù)黎做,如果目標(biāo)對象過多叉跛,則會產(chǎn)生很多代理類松忍。
  2. JDK動態(tài)代理需要目標(biāo)對象實現(xiàn)業(yè)務(wù)接口,代理類只需實現(xiàn)InvocationHandler接口筷厘。
  3. 靜態(tài)代理在編譯時產(chǎn)生class字節(jié)碼文件鸣峭,可以直接使用,效率高酥艳。
  4. 動態(tài)代理必須實現(xiàn)InvocationHandler接口摊溶,通過反射代理方法,比較消耗系統(tǒng)性能充石,但可以減少代理類的數(shù)量莫换,使用更靈活。
  5. cglib代理無需實現(xiàn)接口骤铃,通過生成類字節(jié)碼實現(xiàn)代理拉岁,比反射稍快,不存在性能問題惰爬,但cglib會繼承目標(biāo)對象喊暖,需要重寫方法,所以目標(biāo)對象不能為final類撕瞧。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陵叽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丛版,更是在濱河造成了極大的恐慌巩掺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件页畦,死亡現(xiàn)場離奇詭異胖替,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寇漫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門刊殉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人州胳,你說我怎么就攤上這事记焊。” “怎么了栓撞?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵遍膜,是天一觀的道長碗硬。 經(jīng)常有香客問我,道長瓢颅,這世上最難降的妖魔是什么恩尾? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮挽懦,結(jié)果婚禮上翰意,老公的妹妹穿的比我還像新娘。我一直安慰自己信柿,他們只是感情好冀偶,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渔嚷,像睡著了一般进鸠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上形病,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天客年,我揣著相機(jī)與錄音,去河邊找鬼漠吻。 笑死量瓜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的侥猩。 我是一名探鬼主播榔至,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼欺劳!你這毒婦竟也來了唧取?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤划提,失蹤者是張志新(化名)和其女友劉穎枫弟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹏往,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淡诗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了伊履。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韩容。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖唐瀑,靈堂內(nèi)的尸體忽然破棺而出群凶,到底是詐尸還是另有隱情,我是刑警寧澤哄辣,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布请梢,位于F島的核電站赠尾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏毅弧。R本人自食惡果不足惜气嫁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望够坐。 院中可真熱鬧寸宵,春花似錦、人聲如沸咆霜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛾坯。三九已至,卻和暖如春疏遏,著一層夾襖步出監(jiān)牢的瞬間脉课,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工财异, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倘零,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓戳寸,卻偏偏與公主長得像呈驶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疫鹊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容