CGlib簡單介紹__java

來源:互聯網
上載者:User
CGlib概述:
cglib( Code Generation Library)是一個強大的,高效能,高品質的Code產生類庫。它可以在運行期擴充Java類與實現Java介面。
cglib封裝了asm,可以在運行期動態產生新的class。
cglib用於AOP,jdk中的proxy必須基於介面,cglib卻沒有這個限制。

CGlib應用:
以一個執行個體在簡單介紹下cglib的應用。
我們類比一個虛擬情境,關於資訊的管理。

1)原始需求是任何人可以操作資訊的create,update,delete,query操作。
InfoManager.java--封裝對資訊的操作
public   class  InfoManager {
     //  類比查詢操作
     public   void  query() {
        System.out.println( " query " );
    }
     //  類比建立操作
     public   void  create() {
        System.out.println( " create " );
    }
     //  類比更新操作
     public   void  update() {
        System.out.println( " update " );
    }
     //  類比刪除操作
     public   void  delete() {
        System.out.println( " delete " );
    }
} InfoManagerFactory.java--工廠類
public   class  InfoManagerFactory {
     private   static  InfoManager manger  =   new  InfoManager();
     /**
     * 建立原始的InfoManager
     * 
     *  @return
      */
     public   static  InfoManager getInstance() {
         return  manger;
    }
} client.java--供用戶端調用
public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.anyonecanManager();
    }

     /**
     * 類比:沒有任何許可權要求,任何人都可以操作
      */
     public   void  anyonecanManager() {
        System.out.println( " any one can do manager " );
        InfoManager manager  =  InfoManagerFactory.getInstance();
        doCRUD(manager);
        separatorLine();
    }

     /**
     * 對Info做增加/更新/刪除/查詢操作
     * 
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一個分隔行,用於區分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

} 至此,沒有涉及到cglib的內容,因為需求太簡單了,但是接下來,需求發生了改變,要求:

2)只有一個叫“maurice”的使用者登入,才允許對資訊進行create,update,delete,query的操作。
怎麼辦。難道在每個方法前,都加上一個許可權判斷嗎。這樣重複邏輯太多了,於是乎想到了Proxy(代理模式),但是原先的InfoManager也沒有實現介面,不能採用jdk的proxy。那麼cglib在這邊就要隆重登場。
一旦使用cgblig,只需要添加一個MethodInterceptor的類以及修改factory代碼就可以實現這個需求。
AuthProxy.java--許可權校正代理類
public   class  AuthProxy  implements  MethodInterceptor {

     private  String name;  //  會員登入名稱

     public  AuthProxy(String name) {
         this .name  =  name;
    }

     /**
     * 許可權校正,如果會員名為:maurice,則有許可權做操作,否則提示沒有許可權
      */
    @Override
     public  Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)  throws  Throwable {
         if  ( ! " maurice " .equals( this .name)) {
            System.out.println( " AuthProxy:you have no permits to do manager! " );
             return   null ;
        }
         return  proxy.invokeSuper(obj, args);
    }

     public  String getName() {
         return  name;
    }

     public   void  setName(String name) {
         this .name  =  name;
    }

} InfoManagerFactory.java--代碼變動如下:
public   class  InfoManagerFactory {

     /**
     * 建立帶有許可權檢驗的InfoManager
     * 
     *  @param  auth
     *  @return
      */
     public   static  InfoManager getAuthInstance(AuthProxy auth) {
        Enhancer enhancer  =   new  Enhancer();
        enhancer.setSuperclass(InfoManager. class );
        enhancer.setCallback(auth);
         return  (InfoManager) enhancer.create();
    }

    
}
client.java--代碼修改如下
public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.haveNoAuthManager();
        c.haveAuthManager();
    }

     /**
     * 類比:登入會員沒有許可權
      */
     public   void  haveNoAuthManager() {
        System.out.println( " the loginer's name is not maurice,so have no permits do manager " );
        InfoManager noAuthManager  =  InfoManagerFactory.getAuthInstance( new  AuthProxy( " maurice1 " ));
        doCRUD(noAuthManager);
        separatorLine();
    }

     /**
     * 類比:登入會員有許可權
      */
     public   void  haveAuthManager() {
        System.out.println( " the loginer's name is maurice,so have permits do manager " );
        InfoManager authManager  =  InfoManagerFactory.getAuthInstance( new  AuthProxy( " maurice " ));
        doCRUD(authManager);
        separatorLine();
    }

     /**
     * 對Info做增加/更新/刪除/查詢操作
     * 
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一個分隔行,用於區分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

} 執行下代碼,發現這時client端中已經加上了許可權校正。
同樣是InfoManager,為什麼這時能多了許可權的判斷呢。Factory中 enhancer.create()返回的到底是什麼對象呢。這個疑問將在第三部分CGlib中解釋。
這邊的代碼,其實是介紹了cglib中的enhancer功能.

到這裡,參照上面的代碼,就可以使用cglib帶來的aop功能了。但是為了更多介紹下cglib的功能,類比需求再次發生變化:

3)由於query功能使用者maurice才能使用,招來其他使用者的強烈的抱怨,所以許可權再次變更,只有create,update,delete,才需要許可權保護,query任何人都可以使用。
怎麼辦。採用AuthProxy,使得InfoManager中的所有方法都被代理,加上了許可權的判斷。當然,最容易想到的辦法,就是在AuthProxy的intercept的方法中再做下判斷,如果代理的method是query,不需要許可權驗證。這麼做,可以,但是一旦邏輯比較複雜的時候,intercept這個方法要做的事情會很多,邏輯會異常的複雜。
幸好,cglib還提供了CallbackFilter。使用CallbackFilter,可以明確表明,被代理的類(InfoManager)中不同的方法,被哪個攔截器(interceptor)攔截。
AuthProxyFilter.java
public   class  AuthProxyFilter  implements  CallbackFilter {

     private   static   final   int  AUTH_NEED      =   0 ;
     private   static   final   int  AUTH_NOT_NEED  =   1 ;

     /**
     * <pre>
     * 選擇使用的proxy
     * 如果調用query函數,則使用第二個proxy
     * 否則,使用第一個proxy
     * </pre>
      */
    @Override
     public   int  accept(Method method) {
         if  ( " query " .equals(method.getName())) {
             return  AUTH_NOT_NEED;
        }
         return  AUTH_NEED;
    }

} 這段代碼什麼意思。其中的accept方法的意思是說,如果代理的方法是query(),那麼使用第二個攔截器去攔截,如果代理的方法不是query(),那麼使用第一個攔截器去攔截。所以我們只要再寫一個攔截器,不做許可權校正就行了。(其實,cglib中的NoOp.INSTANCE就是一個空的攔截器,只要配置上這個就可以了。)
InfoManagerFactory.java--代碼修改如下:(配置不同的攔截器和filter)
public   class  InfoManagerFactory {

     /**
     * 建立不同許可權要求的InfoManager
     * 
     *  @param  auth
     *  @return
      */
     public   static  InfoManager getSelectivityAuthInstance(AuthProxy auth) {
        Enhancer enhancer  =   new  Enhancer();
        enhancer.setSuperclass(InfoManager. class );
        enhancer.setCallbacks( new  Callback[] { auth, NoOp.INSTANCE });
        enhancer.setCallbackFilter( new  AuthProxyFilter());
         return  (InfoManager) enhancer.create();
    }

} 記住:setCallbacks中的攔截器(interceptor)的順序,一定要和 CallbackFilter裡面指定的順序一致。。切忌。

Client.java
public   class  Client {

     public   static   void  main(String[] args) {
        Client c  =   new  Client();
        c.selectivityAuthManager();
    }
    
     /**
     * 類比:沒有許可權的會員,可以作查詢操作
      */
     public   void  selectivityAuthManager() {
        System.out.println( " the loginer's name is not maurice,so have no permits do manager except do query operator " );
        InfoManager authManager  =  InfoManagerFactory.getSelectivityAuthInstance( new  AuthProxy( " maurice1 " ));
        doCRUD(authManager);
        separatorLine();
    }

     /**
     * 對Info做增加/更新/刪除/查詢操作
     * 
     *  @param  manager
      */
     private   void  doCRUD(InfoManager manager) {
        manager.create();
        manager.update();
        manager.delete();
        manager.query();
    }

     /**
     * 加一個分隔行,用於區分
      */
     private   void  separatorLine() {
        System.out.println( " ################################ " );
    }

} 此時,對於query的許可權校正已經被去掉了。


通過一個類比需求,簡單介紹了cglib aop功能的使用。
CGlib應用非常廣,在spring,hibernate等架構中,被大量的使用。


CGlib原理:
cglib神奇嗎。其實一旦瞭解cglib enhancer的原理,一切就真相大白了。
剛才在第二部分中,有個疑問:enhancer.create()到底返回了什麼對象。

其實在剛才的例子中,cglib在代碼運行期,動態產生了InfoManager的子類,並且根據CallbackFilter的accept方法,覆寫了InfoManager中的所有方法--去執行相應的MethodInterceptor的intercept方法。

有興趣的朋友可以看看我反編譯的InfoManager的子類,就可以很明白知道具體的實現了。(需要有耐心才可以)
InfoManager$$EnhancerByCGLIB$$de624598.jad
//  Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
//  Jad home page:  http://www.geocities.com/kpdus/jad.html
//  Decompiler options: packimports(3) 
//  Source File Name:   <generated>

package  cn.eulic.codelab.cglib;

import  java.lang.reflect.Method;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.