cglib代理的簡單案例

1.  cglib概述: java

     code Generation Libary (cglib) ,是一個強大的、高性能、高質量的COde生成類庫。它能夠在運行期擴展Java類與實現Java接口。 spring

     cglib封裝了asm,能夠在運行期動態生成新的class。 框架

     cglib用於AOP,JDK中的proxy必須基於接口,cglib沒有這個限制 ide

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等框架中,被大量的使用。
相關文章
相關標籤/搜索