CGlib是什麼?

CGlib是什麼?
CGlib是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。
當然這些實際的功能是asm所提供的,asm又是什麼?Java字節碼操控框架,具體是什麼大家可以上網查一查,畢竟我們這裏所要討論的是cglib,
cglib就是封裝了asm,簡化了asm的操作,實現了在運行期動態生成新的class。
可能大家還感覺不到它的強大,現在就告訴你。
實際上CGlib爲spring aop提供了底層的一種實現;爲hibernate使用cglib動態生成VO/PO (接口層對象)。

下面我們將通過一個具體的事例來看一下CGlib體驗一下CGlib。
* CGlib 2.13
* ASM 2.23
以一個實例在簡單介紹下cglib的應用。
我們模擬一個虛擬的場景,模擬對錶的操作。
1. 開始我們對錶提供了CRUD方法。
我們現在創建一個對Table操作的DAO類。
Java代碼  收藏代碼
  1. public class TableDAO {  
  2.     public void create(){  
  3.         System.out.println("create() is running !");  
  4.     }  
  5.     public void query(){  
  6.         System.out.println("query() is running !");  
  7.     }  
  8.     public void update(){  
  9.         System.out.println("update() is running !");  
  10.     }  
  11.     public void delete(){  
  12.         System.out.println("delete() is running !");  
  13.     }  
  14. }  

OK,它就是一個javaBean,提供了CRUD方法的javaBean。
下面我們創建一個DAO工廠,用來生成DAO實例。
Java代碼  收藏代碼
  1. public class TableDAOFactory {  
  2.     private static TableDAO tDao = new TableDAO();  
  3.     public static TableDAO getInstance(){  
  4.         return tDao;  
  5.     }  
  6. }  

接下來我們創建客戶端,用來調用CRUD方法。
Java代碼  收藏代碼
  1. public class Client {  
  2.   
  3.     public static void main(String[] args) {  
  4.         TableDAO tableDao = TableDAOFactory.getInstance();  
  5.         doMethod(tableDao);  
  6.     }  
  7.     public static void doMethod(TableDAO dao){  
  8.         dao.create();  
  9.         dao.query();  
  10.         dao.update();  
  11.         dao.delete();  
  12.     }  
  13. }  

OK,完成了,CRUD方法完全被調用了。當然這裏並沒有CGlib的任何內容。問題不會這麼簡單的就結束,新的需求來臨了。
2. 變化隨之而來,Boss告訴我們這些方法不能開放給用戶,只有“張三”纔有權使用。阿~!怎麼辦,難道我們要在每個方法上面進行判斷嗎?
好像這麼做也太那啥了吧,對了對了Proxy可能是最好的解決辦法。jdk的代理就可以解決了。 好了我們來動手改造吧。等等jdk的代理需要實現接口,這樣,
我們的dao類需要改變了。既然不想改動dao又要使用代理,我們這就請出CGlib。
我們只需新增一個權限驗證的方法攔截器。
Java代碼  收藏代碼
  1. public class AuthProxy implements MethodInterceptor {  
  2.     private String name ;  
  3.     //傳入用戶名稱  
  4.     public AuthProxy(String name){  
  5.         this.name = name;  
  6.     }  
  7.     public Object intercept(Object arg0, Method arg1, Object[] arg2,  
  8.             MethodProxy arg3) throws Throwable {  
  9.         //用戶進行判斷  
  10.         if(!"張三".equals(name)){  
  11.             System.out.println("你沒有權限!");  
  12.             return null;  
  13.         }  
  14.         return arg3.invokeSuper(arg0, arg2);  
  15.     }  
  16. }  

當然不能忘了對我們的dao工廠進行修改,我們提供一個使用代理的實例生成方法
Java代碼  收藏代碼
  1. public static TableDAO getAuthInstance(AuthProxy authProxy){  
  2.     Enhancer en = new Enhancer();  
  3.     //進行代理  
  4.     en.setSuperclass(TableDAO.class);  
  5.     en.setCallback(authProxy);  
  6.     //生成代理實例  
  7.     return (TableDAO)en.create();  
  8. }  

我們這就可以看看客戶端的實現了。添加了兩個方法用來驗證不同用戶的權限。
Java代碼  收藏代碼
  1. public static void haveAuth(){  
  2.     TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("張三"));  
  3.     doMethod(tDao);  
  4. }  
  5. public static void haveNoAuth(){  
  6.     TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四"));  
  7.     doMethod(tDao);  
  8. }  

OK,"張三"的正常執行,"李四"的沒有執行。
看到了嗎?簡單的aop就這樣實現了
難道就這樣結束了麼?
3. Boss又來訓話了,不行不行,現在除了"張三"其他人都用不了了,現在不可以這樣。他們都來向我反映了,必須使用開放查詢功能。
哈哈,現在可難不倒我們了,因爲我們使用了CGlib。當然最簡單的方式是去修改我們的方法攔截器,不過這樣會使邏輯變得複雜,且
不利於維護。還好CGlib給我們提供了方法過濾器(CallbackFilter),CallbackFilte可以明確表明,被代理的類中不同的方法,
被哪個攔截器所攔截。下面我們就來做個過濾器用來過濾query方法。
Java代碼  收藏代碼
  1. public class AuthProxyFilter implements CallbackFilter{  
  2.     public int accept(Method arg0) {  
  3.         if(!"query".equalsIgnoreCase(arg0.getName()))  
  4.             return 0;  
  5.         return 1;  
  6.     }  
  7.   
  8. }  

OK,可能大家會對return 0 or 1感到困惑,用到的時候就會講解,當然下面就會用到了。
我們在工場中新增一個使用了過濾器的實例生成方法。
Java代碼  收藏代碼
  1. public static TableDAO getAuthInstanceByFilter(AuthProxy authProxy){  
  2.     Enhancer en = new Enhancer();  
  3.     en.setSuperclass(TableDAO.class);  
  4.     en.setCallbacks(new Callback[]{authProxy,NoOp.INSTANCE});  
  5.     en.setCallbackFilter(new AuthProxyFilter());  
  6.     return (TableDAO)en.create();  
  7. }  

看到了嗎setCallbacks中定義了所使用的攔截器,其中NoOp.INSTANCE是CGlib所提供的實際是一個沒有任何操作的攔截器,
他們是有序的。一定要和CallbackFilter裏面的順序一致。明白了嗎?上面return返回的就是返回的順序。也就是說如果調用query方法就使用NoOp.INSTANCE進行攔截。
現在看一下客戶端代碼。
Java代碼  收藏代碼
  1. public static void haveAuthByFilter(){  
  2.     TableDAO tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("張三"));  
  3.     doMethod(tDao);  
  4.   
  5.     tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四"));  
  6.     doMethod(tDao);  
  7. }  

ok,現在"李四"也可以使用query方法了,其他方法仍然沒有權限。
哈哈,當然這個代理的實現沒有任何侵入性,無需強制讓dao去實現接口。

如果大家對java的深入研究有興趣
可以加入Q羣:46176507 共同進步學習
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章