• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 非官方解讀代理模式

    標簽: 設計模式

    代理模式(Proxy) : 代理模式就是多一個代理類出來,替原對象進行一些操作.對方法進行加強.而代理類充當一個中介的角色.我們不直接調用原方法.而是通過代理類進行調用,中間可進行自定義處理.Spring Aop中的通知就是由此而來.代理分為靜態代理,動態代理(Jdk代理),cglib代理三種,下文將進行闡述.

    作者是個二吊子,如果描述有誤請指出.


    使用場景

    我們突然接到一個需求,需要對某些具有特殊身份的數據進行驗證,驗證其合法性.這個時候傳統操作是直接改動原有代碼,增加相應處理邏輯.于是乎我們一頓操作發現有三個地方需要驗證.于是臉滾鍵盤對著三個地方進行代碼改動.一頓輸出后,需求解決,測試,上線,完美閉環.但是第二天我們又接到需求,需要對普通身份的數據也進行驗證.這個時候我們就發現,我們又要操作三個地方.可真是新三年,舊三年,縫縫補補又三年.長此以往我們代碼的可讀性越來越差,維護起來要命.于是引出了代理模式.

    靜態代理

    uml圖
    靜態代理uml

    抽象接口: ITeacherDao, 實現類: TeacherDao, 代理類: TeacherDaoProxy ,客戶端 : Client

    /**
     * @Description: 接口類
     * @Author: gaofan
     * @Date: 2020/3/24 12:02
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public interface ITeacherDao {
    
        public void teach();
    }
    
    
    /**
     * @Description: 被代理類
     * @Author: gaofan
     * @Date: 2020/3/24 12:03
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class TeacherDao implements  ITeacherDao {
        @Override
        public void teach() {
            System.out.println("王老師正在講課");
        }
    }
    
    /**
     * @Description: 代理類
     * @Author: gaofan
     * @Date: 2020/3/24 12:03
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class TeacherDaoProxy implements ITeacherDao{
    
        private TeacherDao teacherDao;
    
        @Override
        public void teach() {
            System.out.println("打開課件");
            teacherDao.teach();
            System.out.println("關閉課件");
        }
    
        public TeacherDaoProxy(TeacherDao teacherDao) {
            this.teacherDao = teacherDao;
        }
    }
    
    /**
     * @Description: TODO
     * @Author: gaofan
     * @Date: 2020/3/24 12:05
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class Client {
    
    
        public static void main(String [] args){
            TeacherDaoProxy proxy = new TeacherDaoProxy(new TeacherDao());
            proxy.teach();
        }
    }
    
    

    類型: 靜態代理
    原理: 實現類與代理類均實現抽象類接口,對其方法進行實現.代理類中聚合被代理類,其實現方法中通過聚合代理類調用目標方法.可以在代理類方法中加上我們需要增強的功能與處理.
    缺點: 代理類需要實現接口,代碼編譯時已經確定了.

    動態代理

    通過jdk實現,核心是InvocationHandler , Proxy.newProxyInstance().代理類實現InvocationHandler invoke()方法,我們的增強方法也在這個方法中.通過Proxy.newProxyInstance()產生代理實例進行調用.
    uml圖
    動態代理uml

    動態代理與靜態代理的差別: 我們在代理類中并沒有去實現接口,而是通過聚合的方式來實現.動態擴展,讓類與類之間耦合度降低

    /**
     * @Description: 接口類
     * @Author: gaofan
     * @Date: 2020/3/24 12:02
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public interface ITeacherDao {
    
        void teach();
    
        void say();
    }
    
    
    /**
     * @Description: 具體實現
     * @Author: gaofan
     * @Date: 2020/3/24 12:03
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class TeacherDao implements ITeacherDao {
        @Override
        public void teach() {
            System.out.println("王老師正在講課");
        }
    
        @Override
        public void say() {
            System.out.println("王老師開始吹牛了");
        }
    }
    
    
    /**
     * @Description: 代理類
     * @Author: gaofan
     * @Date: 2020/3/24 12:15
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class ProxyFactory implements InvocationHandler {
    
        private Object object;
    
        public ProxyFactory(Object object) {
            this.object = object;
        }
    
        public Object getProxyInstance() {
            return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass()
                    .getInterfaces(),this);
    //        return object;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(!method.getName().equals("say")){
                System.out.println("打開書本");
            }
            Object obj = method.invoke(object, args);
            if(!method.getName().equals("say")){
                System.out.println("關閉書本");
            }
            return obj;
        }
    }
    
    /**
     * @Description: TODO
     * @Author: gaofan
     * @Date: 2020/3/24 12:17
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class Client {
    
        public static void main(String [] args){
            ProxyFactory factory = new ProxyFactory(new TeacherDao());
            ITeacherDao proxyInstance = (ITeacherDao)factory.getProxyInstance();
            proxyInstance.say();
    
            proxyInstance.teach();
        }
    }
    
    

    類型: 動態代理
    原理: 通過Proxy.newProxyInstance()產生實例,自定義實現InvocationHandler的invoke()方法進行增強.
    缺點: 依賴接口實現,必須要有接口類

    cglib代理

    通過非jdk自帶jar實現,能夠對類進行加強,并不僅限于接口
    uml圖
    cglib uml

    動態代理依賴接口實現,而cglib則是直接對類下手了,內部實現應該是字節碼.留著后邊探索了

    /**
     * @Description: 被代理類
     * @Author: gaofan
     * @Date: 2020/3/24 12:47
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class TeacherDao {
    
        public void teach() {
            System.out.println("王老師正在講課");
        }
    
        public void say() {
            System.out.println("王老師開始吹牛了");
        }
    }
    
    
    
    /**
     * @Description: 代理類
     * @Author: gaofan
     * @Date: 2020/3/24 12:48
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class ProxyFactory implements MethodInterceptor {
    
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        public Object getProxyInstance(){
            // 創建工具類
            Enhancer enhancer = new Enhancer();
            // 設置父類
            enhancer.setSuperclass(target.getClass());
            // 設置回調函數
            enhancer.setCallback(this);
            // 創建子類對象,即代理對象
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
            System.out.println("cglib 代理開始了");
            Object obj = method.invoke(target, objects);
            System.out.println("cglib 代理結束了");
            return obj;
        }
    }
    
    /**
     * @Description: TODO
     * @Author: gaofan
     * @Date: 2020/3/24 12:48
     * @Copyright: 2020 www.withu.top Inc. All rights reserved.
     **/
    public class Client {
    
        public static void main(String[] args) {
            TeacherDao teacherDao = new TeacherDao();
            ProxyFactory factory = new ProxyFactory(teacherDao);
            TeacherDao dao = (TeacherDao) factory.getProxyInstance();
            dao.teach();
    
            dao.say();
        }
    }
    

    原理: 代理類實現MethodInterceptor ,實現其intercept 方法(攔截器),通過Enhancer 工具類設置父類,設置回調,創建子類對象并返回實例.客戶端通過返回實例進行調用.
    優點: 直接對類增強.對接口沒有依賴


    本文借鑒尚硅谷Java設計模式,韓順平圖解java,傳送門

    版權聲明:本文為sky_demo原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/sky_demo/article/details/105072385

    智能推薦

    Spring AOP編程官方文檔解讀之代理機制

    系列文章目錄 第一章 : Spring AOP編程官方文檔解讀之切點 第二章 : Spring AOP編程官方文檔解讀之增強 第三章 : Spring AOP編程官方文檔解讀之增強方法參數 第四章 : Spring AOP編程官方文檔解讀之引介增強 第五章 : Spring AOP編程官方文檔解讀之另類切面Advisor 第六章 : Spring AOP編程官方文檔解讀之代理機制 文章目錄 系列文...

    wmctf web部分wp(非官方qwq

    web_checkin 隊友@小白菜 隨便試了一個content=/flag就出flag了(后期知道是因為文件名的非預期 Make PHP Great Again 看著短短的五行代碼,實在難做嚶嚶嚶 后來得知是session.upload_progress(后知后覺 那就開整! 參考文章了https://www.freebuf.com/news/202819.html 改了一下就開跑! 然后就出來...

    YEOMAN官方文檔非官方翻譯~快速使用(codelab)

    在25分鐘的 codelab(編碼實驗) 中,你將在 Yeoman、FountainJS 的幫助下,通過腳手架構建起一個功能完整的web應用。這個簡單的應用將會用 React、Angular2、Angular1 來編寫。 不知道 React 或者 Angular?沒關系,我們將會幫您渡過難關。然而,我們必須假定你先前已經有了一些 JavaScript 的編程經驗。 通過Yeoman構建這個簡單的應...

    Qt 圖像疊加模式[composition Modes]官方例子 源碼解讀

    前言: 看 qt 的例子 看到個有意思的 圖片質量有壓縮 看起來不美 這個代碼 比我們平常看到的要復雜一點 能學到東西 我把源碼看了一下 在這里在仔細整理說一下 composition 項目結構 一個 shared 文件夾 幾個類 注意 這個 hoverpoints 類沒有用到 因為我沒有開啟 opengl 兩個資源文件 一些美化控件的圖片 兩種 底色圖片 就是那個背景花 一個 html 里面是介...

    SpringBoot非官方教程 | 第十九篇: 驗證表單信息

    轉載請標明出處: http://blog.csdn.net/forezp/article/details/71023817 本文出自方志朋的博客 這篇文篇主要簡述如何在springboot中驗證表單信息。在springmvc工程中,需要檢查表單信息,表單信息驗證主要通過注解的形式。 構建工程 創建一個springboot工程,由于用到了 web 、thymeleaf、validator、el,引入...

    猜你喜歡

    SpringBoot非官方教程 | 第十二篇:springboot集成apidoc

    轉載請標明出處: http://blog.csdn.net/forezp/article/details/71023579 本文出自方志朋的博客 首先聲明下,apidoc是基于注釋來生成文檔的,它不基于任何框架,而且支持大多數編程語言,為了springboot系列的完整性,所以標了個題。 一、apidoc簡介 apidoc通過在你代碼的注釋來生成api文檔的。它對代碼沒有侵入性,只需要你寫好相關的...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    精品国产乱码久久久久久蜜桃不卡