日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

代理模式

 印度阿三17 2019-09-23

一.靜態(tài)代理

首先, 定義接口和接口的實(shí)現(xiàn)類, 然后定義接口的代理對象, 將接口的實(shí)例注入到代理對象中, 然后通過代理對象去調(diào)用真正的實(shí)現(xiàn)類。

目標(biāo)情況:代理類較少且確定

優(yōu)點(diǎn):可以做到在符合開閉原則的情況下對目標(biāo)對象進(jìn)行功能擴(kuò)展。

缺點(diǎn):我們得為每一個服務(wù)都得創(chuàng)建代理類,工作量太大,不易管理。同時接口一旦發(fā)生改變,代理類也得相 應(yīng)修改。

創(chuàng)建步驟 1.創(chuàng)建服務(wù)類接口

2.實(shí)現(xiàn)服務(wù)接口

3.創(chuàng)建代理類

代理類以及實(shí)現(xiàn)服務(wù)接口都需要實(shí)現(xiàn)服務(wù)類接口。

代理類中要有目標(biāo)類對象的引用,然后再代理類的方法里面執(zhí)行目標(biāo)類對象的方法。

// 委托接口
public interface IHelloService {

    /**
     * 定義接口方法
     * @param userName
     * @return
     */
    String sayHello(String userName);

}
// 委托類實(shí)現(xiàn)
public class HelloService implements IHelloService {

    @Override
    public String sayHello(String userName) {
        System.out.println("helloService"   userName);
        return "HelloService"   userName;
    }
}

// 代理類
public class StaticProxyHello implements IHelloService {

    private IHelloService helloService = new HelloService();

    @Override
    public String sayHello(String userName) {
        /** 代理對象可以在此處包裝一下*/
        System.out.println("代理對象包裝禮盒...");
        return helloService.sayHello(userName);
    }
}
// 測試靜態(tài)代理類
public class MainStatic {
    public static void main(String[] args) {
        StaticProxyHello staticProxyHello = new StaticProxyHello();
        staticProxyHello.sayHello("isole");
    }
}

二.動態(tài)代理

不再需要再手動的創(chuàng)建代理類,我們只需要編寫一個動態(tài)處理器就可以了。真正的代理對象由JDK再運(yùn)行時為我們動態(tài)的來創(chuàng)建。

JVM 的類加載機(jī)制中的加載階段要做的三件事情
( 附 Java 中的類加載器 )

  1. 通過一個類的全名或其它途徑來獲取這個類的二進(jìn)制字節(jié)流

  2. 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu)

  3. 在內(nèi)存中生成一個代表這個類的 Class 對象, 作為方法區(qū)中對這個類訪問的入口

而我們要說的動態(tài)代理,主要就發(fā)生在第一個階段, 這個階段類的二進(jìn)制字節(jié)流的來源可以有很多, 比如 zip 包、網(wǎng)絡(luò)、運(yùn)行時計算生成、其它文件生成 (JSP)、數(shù)據(jù)庫獲取。其中運(yùn)行時計算生成就是我們所說的動態(tài)代理技術(shù),在 Proxy 類中, 就是運(yùn)用了 ProxyGenerator.generateProxyClass 來為特定接口生成形式為 *$Proxy 的代理類的二進(jìn)制字節(jié)流。所謂的動態(tài)代理就是想辦法根據(jù)接口或者目標(biāo)對象計算出代理類的字節(jié)碼然后加載進(jìn) JVM 中。

涉及類:java.lang.reflect.Proxy java.lang.reflect.InvocationHandler

// 委托類接口
public interface IHelloService {

    /**
     * 方法1
     * @param userName
     * @return
     */
    String sayHello(String userName);

    /**
     * 方法2
     * @param userName
     * @return
     */
    String sayByeBye(String userName);

}
// 委托類
public class HelloService implements IHelloService {

    @Override
    public String sayHello(String userName) {
        System.out.println(userName   " hello");
        return userName   " hello";
    }

    @Override
    public String sayByeBye(String userName) {
        System.out.println(userName   " ByeBye");
        return userName   " ByeBye";
    }
}
// 中間類
public class JavaProxyInvocationHandler implements InvocationHandler {

    /**
     * 中間類持有委托類對象的引用,這里會構(gòu)成一種靜態(tài)代理關(guān)系
     */
    private Object obj ;

    /**
     * 有參構(gòu)造器,傳入委托類的對象
     * @param obj 委托類的對象
     */
    public JavaProxyInvocationHandler(Object obj){
        this.obj = obj;

    }

    /**
     * 動態(tài)生成代理類對象,Proxy.newProxyInstance
     * @return 返回代理類的實(shí)例
     */
    public Object newProxyInstance() {
        return Proxy.newProxyInstance(
                //指定代理對象的類加載器
                obj.getClass().getClassLoader(),
                //代理對象需要實(shí)現(xiàn)的接口,可以同時指定多個接口
                obj.getClass().getInterfaces(),
                //方法調(diào)用的實(shí)際處理者,代理對象的方法調(diào)用都會轉(zhuǎn)發(fā)到這里
                this);
    }


    /**
     *
     * @param proxy 代理對象
     * @param method 代理方法
     * @param args 方法的參數(shù)
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke before");
        Object result = method.invoke(obj, args);
        System.out.println("invoke after");
        return result;
    }
}
// 測試動態(tài)代理類
public class MainJavaProxy {
    public static void main(String[] args) {
        JavaProxyInvocationHandler proxyInvocationHandler = new JavaProxyInvocationHandler(new HelloService());
        IHelloService helloService = (IHelloService) proxyInvocationHandler.newProxyInstance();
        helloService.sayByeBye("paopao");
        helloService.sayHello("yupao");
    }

}

中間類要實(shí)現(xiàn)invocationHandler接口

中間類通過反射動態(tài)生成的代理類

代理類的任何方法都會先執(zhí)行invoke

雖然相對于靜態(tài)代理,動態(tài)代理大大減少了我們的開發(fā)任務(wù),同時減少了對業(yè)務(wù)接口的依賴,降低了耦合度。但是還是有一點(diǎn)點(diǎn)小小的遺憾之處,那就是它始終無法擺脫僅支持interface代理

三.CGLIB代理

JDK 動態(tài)代理依賴接口實(shí)現(xiàn),而當(dāng)我們只有類沒有接口的時候就需要使用另一種動態(tài)代理技術(shù) CGLIB 動態(tài)代理。首先 CGLIB 動態(tài)代理是第三方框架實(shí)現(xiàn)的,在 maven 工程中我們需要引入 cglib 的包, 如下:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2</version>
</dependency>

CGLIB 代理是針對類來實(shí)現(xiàn)代理的,原理是對指定的委托類生成一個子類并重寫其中業(yè)務(wù)方法來實(shí)現(xiàn)代理。代理類對象是由 Enhancer 類創(chuàng)建的。CGLIB 創(chuàng)建動態(tài)代理類的模式是:

  1. 查找目標(biāo)類上的所有非 final 的 public 類型的方法 (final 的不能被重寫)

  2. 將這些方法的定義轉(zhuǎn)成字節(jié)碼

  3. 將組成的字節(jié)碼轉(zhuǎn)換成相應(yīng)的代理的 Class 對象然后通過反射獲得代理類的實(shí)例對象

  4. 實(shí)現(xiàn) MethodInterceptor 接口, 用來處理對代理類上所有方法的請求

// 委托類,是一個簡單類
public class CglibHelloClass {
    /**
     * 方法1
     * @param userName
     * @return
     */
    public String sayHello(String userName){
        System.out.println("目標(biāo)對象的方法執(zhí)行了");
        return userName   " sayHello";
    }

    public String sayByeBye(String userName){
        System.out.println("目標(biāo)對象的方法執(zhí)行了");
        return userName   " sayByeBye";
    }

}
/**
 * CglibInterceptor 用于對方法調(diào)用攔截以及回調(diào)
 *
 */
public class CglibInterceptor implements MethodInterceptor {
    /**
     * CGLIB 增強(qiáng)類對象,代理類對象是由 Enhancer 類創(chuàng)建的,
     * Enhancer 是 CGLIB 的字節(jié)碼增強(qiáng)器,可以很方便的對類進(jìn)行拓展
     */
    private Enhancer enhancer = new Enhancer();

    /**
     *
     * @param obj  被代理的對象
     * @param method 代理的方法
     * @param args 方法的參數(shù)
     * @param proxy CGLIB方法代理對象
     * @return  cglib生成用來代替Method對象的一個對象,使用MethodProxy比調(diào)用JDK自身的Method直接執(zhí)行方法效率會有提升
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("方法調(diào)用之前");
        Object o = proxy.invokeSuper(obj, args);
        System.out.println("方法調(diào)用之后");
        return o;
    }


    /**
     * 使用動態(tài)代理創(chuàng)建一個代理對象
     * @param c
     * @return
     */
    public  Object newProxyInstance(Class<?> c) {
        /**
         * 設(shè)置產(chǎn)生的代理對象的父類,增強(qiáng)類型
         */
        enhancer.setSuperclass(c);
        /**
         * 定義代理邏輯對象為當(dāng)前對象,要求當(dāng)前對象實(shí)現(xiàn) MethodInterceptor 接口
         */
        enhancer.setCallback(this);
        /**
         * 使用默認(rèn)無參數(shù)的構(gòu)造函數(shù)創(chuàng)建目標(biāo)對象,這是一個前提,被代理的類要提供無參構(gòu)造方法
         */
        return enhancer.create();
    }
}

//測試類
public class MainCglibProxy {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        CglibHelloClass cglibHelloClass = (CglibHelloClass) cglibProxy.newProxyInstance(CglibHelloClass.class);
        cglibHelloClass.sayHello("isole");
        cglibHelloClass.sayByeBye("sss");
    }
}

java動態(tài)代理和gclib代理的區(qū)別

java動態(tài)代理基于接口動態(tài)生成實(shí)現(xiàn)類

gclib代理基于繼承動態(tài)生成子類

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多