1. 程式人生 > >Java動態代理與Cglib庫應用

Java動態代理與Cglib庫應用

轉載:http://blog.csdn.net/zhoudaxia/article/details/30591941

JDK動態代理

  代理模式是常用的java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務。 
  按照代理的建立時期,代理類可以分為兩種。 
  靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。 
  動態代理:在程式執行時,運用反射機制動態建立而成。 

  為什麼使用動態代理?因為動態代理可以對請求進行任何處理。
  哪些地方需要動態代理?不允許直接訪問某些類;對訪問要做特殊處理等。
 目前Java開發包中包含了對動態代理的支援,但是其實現只支援對介面的的實現。 其實現主要通過java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler介面。 Proxy類主要用來獲取動態代理物件,InvocationHandler介面用來約束呼叫者實現。

  以下為模擬案例,通過動態代理實現在方法呼叫前後向控制檯輸出兩句字串。

  定義一個HelloWorld介面:

  1. package com.ljq.test;  
  2.  /** 
  3.  * 定義一個HelloWorld介面 
  4.  *  
  5.  * @author jiqinlin 
  6.  * 
  7.  */
  8.  publicinterface HelloWorld {  
  9.     publicvoid sayHelloWorld();  
  10. }  

  類HelloWorldImpl是HelloWorld介面的實現:

  1. package com.ljq.test;  
  2.  /** 
  3.  * 類HelloWorldImpl是HelloWorld介面的實現 
  4.  *  
  5.  * @author jiqinlin 
  6.  * 
  7.  */
  8.  publicclass HelloWorldImpl implements HelloWorld{  
  9.     public
    void sayHelloWorld() {  
  10.         System.out.println("HelloWorld!");  
  11.     }  
  12. }  
  HelloWorldHandler是 InvocationHandler介面實現:
  1. package com.ljq.test;  
  2.  import java.lang.reflect.InvocationHandler;  
  3.  import java.lang.reflect.Method;  
  4.  /** 
  5.  * 實現在方法呼叫前後向控制檯輸出兩句字串 
  6.  *  
  7.  * @author jiqinlin 
  8.  * 
  9.  */
  10.  publicclass HelloWorldHandler implements InvocationHandler{  
  11.     //要代理的原始物件
  12.      private Object obj;  
  13.     public HelloWorldHandler(Object obj) {  
  14.         super();  
  15.         this.obj = obj;  
  16.     }  
  17.     /** 
  18.      * 在代理例項上處理方法呼叫並返回結果 
  19.      *  
  20.      * @param proxy 代理類 
  21.      * @param method 被代理的方法 
  22.      * @param args 該方法的引數陣列 
  23.      */
  24.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  25.         Object result = null;  
  26.         //呼叫之前
  27.          doBefore();  
  28.         //呼叫原始物件的方法
  29.         result=method.invoke(obj, args);  
  30.         //呼叫之後
  31.         doAfter();  
  32.         return result;  
  33.     }  
  34.     privatevoid doBefore(){  
  35.         System.out.println("before method invoke");  
  36.     }  
  37.     privatevoid doAfter(){  
  38.         System.out.println("after method invoke");  
  39.     }  
  40. }  
  測試類:
  1. package com.ljq.test;  
  2. import java.lang.reflect.InvocationHandler;  
  3. import java.lang.reflect.Proxy;  
  4. publicclass HelloWorldTest {  
  5.     publicstaticvoid main(String[] args) {  
  6.         HelloWorld helloWorld=new HelloWorldImpl();  
  7.         InvocationHandler handler=new HelloWorldHandler(helloWorld);  
  8.         //建立動態代理物件
  9.         HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(  
  10.             helloWorld.getClass().getClassLoader(),  
  11.             helloWorld.getClass().getInterfaces(),  
  12.             handler);  
  13.         proxy.sayHelloWorld();  
  14.     }  
  15. }  
  執行結果為:
  1. before method invoke  
  2. HelloWorld!  
  3. after method invoke  

  基本流程:用Proxy類建立目標類的動態代理,建立時需要指定一個自己實現InvocationHandler介面的回撥類的物件,這個回撥類中有一個invoke()用於攔截對目標類各個方法的呼叫。建立好代理後就可以直接在代理上呼叫目標物件的各個方法。

  JDK自從1.3版本開始,就引入了動態代理,並且經常被用來動態地建立代理。JDK的動態代理用起來非常簡單,但它有一個限制,就是使用動態代理的物件必須實現一個或多個介面。比如上面的HelloWorldImpl類,實現了HelloWorld介面,所以可以用JDK的動態代理。如果想代理沒有實現介面的繼承的類,該怎麼辦? CGLIB就是最好的選擇(https://github.com/cglib/cglib,使用apache license 2.0)。其他比較有名的還有從JBoss專案衍生出來的Javassist(https://github.com/jboss-javassist/javassist),這裡介紹Cglib。

Cglib程式碼生成庫

  CGlib是一個強大的,高效能,高質量的Code生成類庫。它可以在執行期擴充套件Java類與實現Java介面。其底層是通過小而快的位元組碼處理框架ASM(http://forge.ow2.org/projects/asm,使用BSD License)來轉換位元組碼並生成新的類。大部分功能實際上是asm所提供的,CGlib只是封裝了asm,簡化了asm的操作,實現了在執行期動態生成新的class。

  CGlib被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截);最流行的OR Mapping工具hibernate也使用CGLIB來代理單端single-ended(多對一和一對一)關聯(對集合的延遲抓取,是採用其他機制實現的);EasyMock和jMock是通過使用模仿(moke)物件來測試java程式碼的包,它們都通過使用CGLIB來為那些沒有介面的類建立模仿(moke)物件。

  CGLIB包的基本程式碼很少,但學起來有一定的困難,主要是缺少文件,API描述過於簡單,這也是開源軟體的一個不足之處。目前CGLIB的版本是cglib-2.2.jar,主要由一下部分組成:
  (1)net.sf.cglib.core:底層位元組碼處理類,他們大部分與ASM有關係。
  (2)net.sf.cglib.transform:編譯期或執行期類和類檔案的轉換。
  (3)net.sf.cglib.proxy :實現建立代理和方法攔截器的類。
  (4)net.sf.cglib.reflect :實現快速反射和C#風格代理的類。
  (5)net.sf.cglib.util:集合排序工具類。
  (6)net.sf.cglib.beans:JavaBean相關的工具類。

  CGLIB包是在ASM之上的一個高級別的層。對代理那些沒有實現介面的類非常有用。本質上,它是通過動態的生成一個子類去覆蓋所要代理類的不是final的方法,並設定好callback,則原有類的每個方法呼叫就會轉變成呼叫使用者定義的攔截方法(interceptors),這比JDK動態代理方法快多了。可見,Cglib的原理是對指定的目標類動態生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類和final方法進行代理。

用Cglib建立動態代理

  下圖表示Cglib常用到的幾類。

圖1 Cglib主要的介面

  建立一個具體類的代理時,通常要用到的CGLIB包的APIs:

  net.sf.cglib.proxy.Callback介面:在CGLIB包中是一個很關鍵的介面,所有被net.sf.cglib.proxy.Enhancer類呼叫的回撥(callback)介面都要繼承這個介面。

  net.sf.cglib.proxy.MethodInterceptor介面:是最通用的回撥(callback)型別,它經常被AOP用來實現攔截(intercept)方法的呼叫。這個介面只定義了一個方法。

  1. public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;  
  當net.sf.cglib.proxy.MethodInterceptor做為所有代理方法的回撥 (callback)時,當對基於代理的方法呼叫時,在呼叫原物件的方法的之前會呼叫這個方法,如圖下圖所示。第一個引數是代理對像,第二和第三個引數分別 是攔截的方法和方法的引數。原來的方法可能通過使用java.lang.reflect.Method物件的一般反射呼叫,或者使用 net.sf.cglib.proxy.MethodProxy物件呼叫。net.sf.cglib.proxy.MethodProxy通常被首選使用,因為它更快。在這個方法中,我們可以在呼叫原方法之前或之後注入自己的程式碼。

圖1

  net.sf.cglib.proxy.MethodInterceptor能夠滿足任何的攔截(interception )需要,當對有些情況下可能過度。為了簡化和提高效能,CGLIB包提供了一些專門的回撥(callback)型別。例如:

  net.sf.cglib.proxy.FixedValue:為提高效能,FixedValue回撥對強制某一特別方法返回固定值是有用的。

  net.sf.cglib.proxy.NoOp:NoOp回撥把對方法呼叫直接委派到這個方法在父類中的實現。

  net.sf.cglib.proxy.LazyLoader:當實際的物件需要延遲裝載時,可以使用LazyLoader回撥。一旦實際物件被裝載,它將被每一個呼叫代理物件的方法使用。

  net.sf.cglib.proxy.Dispatcher:Dispathcer回撥和LazyLoader回撥有相同的特點,不同的是,當代理方法被呼叫時,裝載物件的方法也總要被呼叫。

   net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回撥和Dispatcher一樣,不同的是,它可以把代理物件作為裝載物件方法的一個引數傳遞。

  代理類的所以方法經常會用到回撥(callback),當然你也可以使用net.sf.cglib.proxy.CallbackFilter 有選擇的對一些方法使用回撥(callback),這種考慮周詳的控制特性在JDK的動態代理中是沒有的。在JDK代理中,對 java.lang.reflect.InvocationHandler方法的呼叫對代理類的所有方法都有效。

  CGLIB的代理包也對net.sf.cglib.proxy.Mixin提供支援。基本上,它允許多個物件被繫結到一個單一的大物件。在代理中對方法的呼叫委託到下面相應的物件中。

  接下來我們看看如何使 用CGLIB代理APIs建立代理。

  1、建立一個簡單的代理

CGLIB代理最核心類net.sf.cglib.proxy.Enhancer, 為了建立一個代理,最起碼你要用到這個類。首先,讓我們使用NoOp回撥建立一個代理。

  1. /**  
  2. 相關推薦

    Java動態代理Cglib應用

    轉載:http://blog.csdn.net/zhoudaxia/article/details/30591941JDK動態代理  代理模式是常用的java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事

    java動態代理Cglib

    JDK動態代理   代理模式是常用的Java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託

    Java動態代理CGLIB

    1. 靜態代理模式 因為需要對一些函式進行二次處理,或是某些函式不讓外界知道時,可以使用代理模式,通過訪問第三方,間接訪問原函式的方式,達到以上目的,來看一下代理模式的類圖: interface Hosee{     String sayhi(); }

    Java動態代理在Android的應用

    一、前言 1.1、什麼是代理? 大道理上講代理是一種軟體設計模式,目的地希望能做到程式碼重用。具體上講,代理這種設計模式是通過不直接訪問被代理物件的方式,而訪問被代理物件的方法。這個就好比 A---->B—>C 這種模式。A可以不通過直接與C對話的情

    JDK動態代理CGLIB動態代理應用及原始碼解析

    代理模式 代理模式:為其他物件提供一種代理以控制對這個物件的訪問。 代理模式中有三種角色:Subject抽象主題角色、RealSubject真實主題角色、Proxy代理主題角色。Subject描述了業務行為,RealSubject執行具體的業務邏輯,Prox

    Java動態代理機制詳解(JDK動態代理CGLIB動態代理區別)

    代理是一種常用的設計模式,其目的就是為其他物件提供一個代理以控制對某個物件的訪問。代理類負責為委託類預處理訊息,過濾訊息並轉發訊息,以及進行訊息被委託類執行後的後續處理。在講述動態代理前,我們先通過一個例子瞭解一下什麼是靜態代理,這裡以事務控制為例。 1.靜態

    JDK動態代理CGLIB動態代理

    RR callback arm back 第一個 throw cati proxy clas 一、jdk動態代理 代理目標是 接口實現類的形式 代理的目標對象: 1 public class PersonServiceImpl implements PersonSer

    動態代理cglib

    art jdk動態代理 super tint pri out eth 通過 ble 代理分為靜態代理,jdk動態代理和cglib 1、首先,說一下靜態代理。 定義一個接口    public interface Interface{ void do

    java動態代理CGLIB實現

    ssl return 其他 ase ger pac 父類 linked nic 動態代理(CGlib 與連接池的案例) Cglib代理: 針對類來實現代理,對指定目標 產生一個子類 通過方法攔截技術攔截所有父類方法的調用。 我們要使用cglib代理必須引入 cglib的j

    JDK動態代理CGLib動態代理相關問題

     導讀: 1、JDK動態代理原理是什麼?為什麼不支援類的代理? 2、JDK動態代理例項 3、CGLib代理原理是什麼? 4、CGLib代理例項 5、JDK動態代理與CGLib代理的區別是什麼? 6、總結     注:閱讀本文之前可以先閱讀

    java代理,靜態代理動態代理以及spring aop代理方式,實現原理統一彙總 Spring中AOP的兩種代理方式(Java動態代理CGLIB代理

    若代理類在程式執行前就已經存在,那麼這種代理方式被成為 靜態代理 ,這種情況下的代理類通常都是我們在Java程式碼中定義的。 通常情況下, 靜態代理中的代理類和委託類會實現同一介面或是派生自相同的父類。 一、概述1. 什麼是代理我們大家都知道微商代理,簡單地說就是代替廠家賣商品,廠家“委託”代理為

    JDK動態代理CGLIB 動態代理

    一、JDK動態代理 實現方式:通過反射類獲取目標類的介面實現,進行攔截和擴充套件 優點:通過位元組通過反射獲取目標物件的方法進行攔截 缺點:目標物件類一定要實現介面 示例程式碼: public interface UserService { String get

    jdk動態代理cglib程式碼實現--SpringAop底層原理

    動態代理分為兩類:基於介面的代理和基於繼承的代理 兩類實現的代表是:JDK代理 與 CGlib代理 cglib實現動態代理: 1、定義目標物件: public class RealSubject { //目標物件RealSubject,cglib不

    SpringAOP深入瞭解之jdk動態代理CGlib

    理解AOP 一般我們編寫程式的思想是縱向的,也就是一個方法程式碼從該方法第一行開始往下一步一步走,直到走完最後一行程式碼。也就是說很多業務都需要的比如使用者鑑權,資源釋放等我們都要在每個方法裡面重複再去呼叫。 public void doMethodOne() {

    視覺化說明jdk動態代理cglib動態代理--InvocationHandler--MethodInterceptor

    動態代理是為了實現Aop程式設計,代理的是類物件 【jdk動態代理】被代理的類需要實現介面,針對介面的代理,通過生成一個實現了介面的動態類實現代理 ServiceImpl是被代理類,實現介面Servi

    動態代理cglib代理

       spring的aop(面向切面程式設計)思想總結就是八個字“縱向重複,橫向抽取”。其作用體現在很多方面,例如在Filter中設定字元的編碼格式,Intercepter中賦值引數進行登入校驗等等。以下圖示展示了aop思想的一個重要且常見的用途,我們知道在service的實

    jdk動態代理CGLib的區別

    jdk動態代理與CGLib的區別 2017年09月20日 22:31:10 E_k_in 閱讀數:5151 動態代理proxy與CGLib的區別 標籤: 代理模式 2013-09-03 08:50 19977人閱讀 評論(4)&nbs

    Java動態代理反射詳解

    首先我得先請大家不要誤會,部落格園說轉載的文章放在文章分類裡,原創的文章用隨筆寫,我開先還以為隨筆是拿來寫抒情文的(滑稽),後來才發現不是這樣的,但是自己所有的文章都在文章分類裡了,又懶得搬運,所以我就用js重定向了一下。所以現在標題欄裡進來的都是文章分類哦,大部分都是自己原創的,轉載會註明轉載的url。 廢

    細說java動態代理cglib動態代理

              提到代理,想必大家對設計模式中的靜態代理和動態代理都比較熟悉,小編之前在部落格中對動態和靜態代理進行了對比,這篇博文就只探討java動態代理和cglib動態代理之間的區別; ♚  

    2.1 Spring宣告式事務的實現方式選擇(JDK動態代理cglib

    1、簡介Spring宣告式事務的具體實現方式是動態決定的,與具體配置、以及事務代理物件是否實現介面等有關。2、使用JDK動態代理的情況在滿足下面兩個條件時,Spring會選擇JDK動態代理作為宣告式事務