自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

CGlib:AOP的另一種實(shí)現(xiàn)

開發(fā) 后端
大家都知道,動(dòng)態(tài)代理能夠?qū)崿F(xiàn)AOP,但是它有一個(gè)缺點(diǎn),就是所有被代理的對象必須實(shí)現(xiàn)一個(gè)接口,否則就會(huì)報(bào)異常。那么如果被代理對象沒有實(shí)現(xiàn)接口那該如何實(shí)現(xiàn)AOP呢?當(dāng)然是能的,使用CGlib就可以實(shí)現(xiàn)。

 1、什么是CGlib

  CGlib是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫。它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。然這些實(shí)際的功能是asm所提供的,asm又是什么?Java字節(jié)碼操控框架,具體是什么大家可以上網(wǎng)查一查,畢竟我們這里所要討論的是cglib,cglib就是封裝了asm,簡化了asm的操作,實(shí)現(xiàn)了在運(yùn)行期動(dòng)態(tài)生成新的class。可能大家還感覺不到它的強(qiáng)大,現(xiàn)在就告訴你。實(shí)際上CGlib為spring aop提供了底層的一種實(shí)現(xiàn);為hibernate使用cglib動(dòng)態(tài)生成VO/PO (接口層對象)。

  它的原理就是用Enhancer生成一個(gè)原有類的子類,并且設(shè)置好callback , 則原有類的每個(gè)方法調(diào)用都會(huì)轉(zhuǎn)成調(diào)用實(shí)現(xiàn)了MethodInterceptor接口的proxy的intercept() 函數(shù):
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)
  在intercept()函數(shù)里,你可以在執(zhí)行Object result=proxy.invokeSuper(o,args);來執(zhí)行原有函數(shù),在執(zhí)行前后加入自己的東西,改變它的參數(shù),也可以瞞天過海,完全干別的。說白了,就是AOP中的around advice。

  2、如何使用CGlib

  舉個(gè)例子:比如DAO層有對表的增、刪、改、查操作,如果要對原有的DAO層的增、刪、改、查增加權(quán)限控制的話,修改代碼是非常痛苦的。所以可以用AOP來實(shí)現(xiàn)。但是DAO層沒有使用接口,動(dòng)態(tài)代理不可用。這時(shí)候CGlib是個(gè)很好的選擇。

TableDao.java:

  1. package com.cglib; 
  2.   
  3.  public class TableDao { 
  4.      public void create(){ 
  5.          System.out.println("create() is running..."); 
  6.      } 
  7.      public void delete(){ 
  8.          System.out.println("delete() is running..."); 
  9.      } 
  10.      public void update(){ 
  11.          System.out.println("update() is running..."); 
  12.      } 
  13.      public void query(){ 
  14.          System.out.println("query() is running..."); 
  15.      } 
  16.  }

實(shí)現(xiàn)了MethodInterceptor接口的AuthProxy.java:用來對方法進(jìn)行攔截,增加方法訪問的權(quán)限控制,這里只允許張三訪問。

 

  1. package com.cglib; 
  2.   
  3.  import java.lang.reflect.Method; 
  4.   
  5.  import net.sf.cglib.proxy.MethodInterceptor; 
  6.  import net.sf.cglib.proxy.MethodProxy; 
  7.  //方法攔截器 
  8.  public class AuthProxy implements MethodInterceptor { 
  9.      private String userName; 
  10.      AuthProxy(String userName){ 
  11.          this.userName = userName; 
  12.      } 
  13.      //用來增強(qiáng)原有方法 
  14.      public Object intercept(Object arg0, Method arg1, Object[] arg2, 
  15.              MethodProxy arg3) throws Throwable { 
  16.          //權(quán)限判斷 
  17.          if(!"張三".equals(userName)){ 
  18.              System.out.println("你沒有權(quán)限!"); 
  19.              return null
  20.          } 
  21.          return arg3.invokeSuper(arg0, arg2); 
  22.      } 
  23.  } 

 

 

TableDAOFactory.java:用來創(chuàng)建TableDao的子類的工廠類

  1. package com.cglib; 
  2.   
  3.  import net.sf.cglib.proxy.Callback; 
  4.  import net.sf.cglib.proxy.Enhancer; 
  5.  import net.sf.cglib.proxy.NoOp; 
  6.   
  7.  public class TableDAOFactory { 
  8.      private static TableDao tDao = new TableDao();   
  9.      public static TableDao getInstance(){   
  10.          return tDao;   
  11.      }   
  12.      public static TableDao getAuthInstance(AuthProxy authProxy){   
  13.          Enhancer en = new Enhancer();  //Enhancer用來生成一個(gè)原有類的子類 
  14.          //進(jìn)行代理   
  15.          en.setSuperclass(TableDao.class);  
  16.          //設(shè)置織入邏輯 
  17.          en.setCallback(authProxy);   
  18.          //生成代理實(shí)例   
  19.          return (TableDao)en.create();   
  20.      }  
  21.   } 

測試類Client.java:

  1. package com.cglib; 
  2.   
  3.  public class Client { 
  4.   
  5.      public static void main(String[] args) {   
  6.  //        haveAuth();  
  7.          haveNoAuth(); 
  8.      }   
  9.      public static void doMethod(TableDao dao){   
  10.          dao.create();   
  11.          dao.query();   
  12.          dao.update();   
  13.          dao.delete();   
  14.      }   
  15.      //模擬有權(quán)限 
  16.      public static void haveAuth(){   
  17.          TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("張三"));   
  18.          doMethod(tDao);   
  19.      }   
  20.      //模擬無權(quán)限 
  21.      public static void haveNoAuth(){   
  22.          TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四"));   
  23.          doMethod(tDao);   
  24.      } 
  25.  } 

  這樣就能夠?qū)AO層的方法進(jìn)行權(quán)限控制了。但是如果又改需求了,要把DAO層的query方法讓所有用戶都可以訪問,而其他方法照樣有權(quán)限控制,該如何實(shí)現(xiàn)呢?這可難不倒我們了,因?yàn)槲覀兪褂昧薈Glib。當(dāng)然最簡單的方式是去修改我們的方法攔截器,不過這樣會(huì)使邏輯變得復(fù)雜,且不利于維護(hù)。還好CGlib給我們提供了方法過濾器(CallbackFilter),CallbackFilte可以明確表明,被代理的類中不同的方法,被哪個(gè)攔截器所攔截。下面我們就來做個(gè)過濾器用來過濾query方法。

AuthProxyFilter.java:

  1. package com.cglib; 
  2.   
  3.  import java.lang.reflect.Method; 
  4.   
  5.  import net.sf.cglib.proxy.CallbackFilter; 
  6.  import net.sf.cglib.proxy.NoOp; 
  7.   
  8.  public class AuthProxyFilter implements CallbackFilter { 
  9.   
  10.      public int accept(Method arg0) { 
  11.          /* 
  12.           * 如果調(diào)用的不是query方法,則要調(diào)用authProxy攔截器去判斷權(quán)限 
  13.           */ 
  14.          if(!"query".equalsIgnoreCase(arg0.getName())){ 
  15.              return 0//調(diào)用第一個(gè)方法攔截器,即authProxy 
  16.          } 
  17.          /* 
  18.           * 調(diào)用第二個(gè)方法攔截器,即NoOp.INSTANCE,NoOp.INSTANCE是指不做任何事情的攔截器 
  19.           * 在這里就是任何人都有權(quán)限訪問query方法,所以調(diào)用默認(rèn)攔截器不做任何處理 
  20.           */ 
  21.          return 1;   
  22.      } 
  23.   
  24.  } 

  至于為什么返回0或者1,注釋講的很詳細(xì)。

 

TableDAOFactory.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});  //設(shè)置兩個(gè)方法攔截器 
  5.         en.setCallbackFilter(new AuthProxyFilter());   
  6.        return (TableDao)en.create();   
  7.     }   
  8.  

  這里得注意,en.setCallbacks()方法里的數(shù)組參數(shù)順序就是上面方法的返回值所代表的方法攔截器,如果return 0則使用authProxy攔截器,return 1則使用NoOp.INSTANCE攔截器,NoOp.INSTANCE是默認(rèn)的方法攔截器,不做什么處理。

  下面在測試類中添加如下方法:

  1. //模擬權(quán)限過濾器 
  2.     public static void haveAuthByFilter(){   
  3.         TableDao tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("張三"));   
  4.         doMethod(tDao);   
  5.         tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四"));   
  6.         doMethod(tDao);   
  7.     }   

 

在main方法中調(diào)用該方法,程序運(yùn)行結(jié)果如下:

create() is running...
query() is running...
update() is running...
delete() is running...
你沒有權(quán)限!
query() is running...
你沒有權(quán)限!
你沒有權(quán)限!

  這樣的話,所有用戶都對query方法有訪問權(quán)限了,而其他方法只允許張三訪問。

責(zé)任編輯:周立方 來源: 博客園
相關(guān)推薦

2014-09-17 14:37:06

2018-04-18 07:34:58

2016-03-03 10:29:31

用戶信息改進(jìn)

2016-07-11 16:18:26

互聯(lián)網(wǎng)

2023-06-18 23:19:17

ChatGPTPPT方式

2010-07-21 16:23:09

運(yùn)行telnet程序

2011-12-29 21:28:31

Metro UI

2014-01-13 10:36:53

C++錯(cuò)誤

2019-01-02 08:04:29

GAN損失函數(shù)神經(jīng)網(wǎng)絡(luò)

2011-07-21 14:17:15

Ceylon

2013-09-30 10:13:08

IT女程序員

2009-06-17 12:01:21

Linux

2013-10-21 15:11:15

OrmsqlOrm設(shè)計(jì)

2010-09-02 09:14:35

CSS浮動(dòng)

2015-07-28 13:36:04

2009-06-17 09:05:05

Linux隱藏網(wǎng)絡(luò)鏈接命令

2021-10-20 12:20:08

深度學(xué)習(xí)AI賦能

2019-03-17 15:59:05

Android PAPIAPP

2010-06-09 16:17:20

TCP IP協(xié)議網(wǎng)絡(luò)故

2013-09-12 14:26:47

百度云網(wǎng)盤
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號