代理模式

代理在我們生活中并不陌生,假如我現在餓了,我可以選擇直接去飯店吃,也可以通過外賣平臺下單,比如百度外賣、美團外賣、餓了么這些平臺本身不生產產品,他們只是商家的搬運工,可以理解成外賣平臺就是各種商家的代理。
外賣平臺幫我買份飯并送貨上門,不僅節約了我去飯店排隊的麻煩,可以節約自已很多時間,排隊這些細節的問題我不需要關心,目的就是吃上我想吃的飯就ok。我不想自已親自做的事或著做不到的事(比如中午我需要開個會,沒時間去出去),就可以找個代理幫我去做。
現在各大平臺都在搞活動,只要下單就可以打折,“打折”算是代理的一個活動,除了給了我想吃的飯還幫我省了部分錢(有的平臺送優惠劵)。代理可以幫我完成要做的事情,還可以附加一些代理想做的事情
那我們在開發中什么時候用代理模式呢?
1、自已不想做或著做不到的事
2、需要在現有方法基礎上擴展些功能,比如在謀方法執行前后非侵入式打印log

靜態代理

public class ProxyDemo {
    public static void main(String args[]){
        RealSubject subject = new RealSubject();
        ProxySubject p = new ProxySubject(subject);
        p.request();
    }
}

interface Subject{
    void request();
}

class RealSubject implements Subject{
    public void request(){
        System.out.println("request");
    }
}

class ProxySubject implements Subject{
    private Subject subject;
    public ProxySubject(Subject subject){
        this.subject = subject;
    }
    public void request(){
        System.out.println("調用前");
        subject.request();
        System.out.println("調用后"); 
    }
}

其實代理還有一個作用就是隱藏真正實現細節,做為代理類不需要關心執行的方法是怎么實現的。
按照代理的創建時期,代理類可以分為兩種。
靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態創建而成。

上邊的實現就是一種靜態代理的實現方式,那啥是動態代理呢,說白了Proxy類是通過反射生成的,AOP (面向切面編程)主要是利用動態代理模式的技術來實現的。
動態代理有2種實現方式:
1、使用JDK的Proxy實現的動態代理
2、使用CGlib實現的動態代理

JDK動態代理中包含一個類和一個接口

InvocationHandler接口: 

  public interface InvocationHandler { 
  public Object invoke(Object proxy,Method method,Object[] args) throws   Throwable; 
  } 
  參數說明: 
  Object proxy:指被代理的對象。 
  Method method:要調用的方法 
  Object[] args:方法調用時所需要的參數 

  可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉  ProxySubject。 

Proxy類: 

  Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態地生成    實現類,此類提供了如下的操作方法: 
  public static Object newProxyInstance(ClassLoader loader, Class<?>[]     interfaces, 
  InvocationHandler h) throws IllegalArgumentException 
  參數說明: 
  ClassLoader loader:類加載器 
  Class<?>[] interfaces:得到全部的接口 
  InvocationHandler h:得到InvocationHandler接口的子類實例

實現方式:

public class DynamicProxyDemo01 {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();    //1.創建委托對象
        ProxyHandler handler = new ProxyHandler(realSubject);    //2.創建調用處理器對象
        Subject proxySubject = (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
                                                        RealSubject.class.getInterfaces(), handler);    //3.動態生成代理對象
        proxySubject.request();    //4.通過代理對象調用方法
    }
}

/**
 * 接口
 */
interface Subject{
    void request();
}

/**
 * 委托類
 */
class RealSubject implements Subject{
    public void request(){
        System.out.println("====RealSubject Request====");
    }
}
/**
 * 代理類的調用處理器
 */
class ProxyHandler implements InvocationHandler{
    private Subject subject;
    public ProxyHandler(Subject subject){
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("調用前");      
        Object result = method.invoke(subject, args);
        System.out.println("調用后");
        return result;
    }
}

使用CGlib實現的動態代理


public class DynamicProxyDemo02 {  
              
            public static void main(String[] args) {  
                RealSubjectCglib cglib=new RealSubjectCglib();  
                RealSubject realSubject=(RealSubject)cglib.getInstance(new RealSubject());  
                realSubject.request();  
            }  
/**
 *沒有實現接口的委拖類
 */
class RealSubject {
    public void request(){
        System.out.println("====RealSubject Request====");
    }
}

    public class RealSubjectCglib implements MethodInterceptor {  
            private Object target;  
          
            /** 
             * 創建代理對象 
             *  
             * @param target 
             * @return 
             */  
            public Object getInstance(Object target) {  
                this.target = target;  
                Enhancer enhancer = new Enhancer();  
                enhancer.setSuperclass(this.target.getClass());  
                // 回調方法  
                enhancer.setCallback(this);  
                // 創建代理對象  
                return enhancer.create();  
            }  
          
            @Override  
            // 回調方法  
            public Object intercept(Object obj, Method method, Object[] args,  MethodProxy proxy) throws Throwable {  
                System.out.println("調用前");  
                proxy.invokeSuper(obj, args);  
                System.out.println("調用后");  
                return null;  
            }  
          
        }  
        }  


JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容

  • 以前看了很多博客文章,一段時間后,對JDK動態代理還是模模糊糊。這次從思考方式上做一個梳理和推理,徹底搞懂動態代理...
    hanxingruo閱讀 792評論 0 4
  • 原文連接 簡介 Java編程的目標是實現現實不能完成的,優化現實能夠完成的,是一種虛擬技術。生活中的方方面面都可以...
    zjk_00閱讀 354評論 0 0
  • 代理模式是常用的結構型設計模式之一,當無法直接訪問某個對象或訪問某個對象存在困難時可以通過一個代理對象來間接訪問,...
    SnDragon閱讀 1,315評論 2 4
  • 什么是代理模式 代理模式是對象的結構模式。代理模式為其他對象提供一種代理以控制對這個對象的訪問。簡單來說,在某些情...
    walidake閱讀 3,227評論 4 27
  • 生活不止眼前的詩,還有遠方你看不到的茍且。 翻朋友圈的的時候無意看到一篇文章:來自X博士的一篇論文截稿,名字叫《帶...
    河對岸的窗閱讀 598評論 0 2