cglib 是什麼?cglib 是一個強大的,高性能,高質量的代碼生成類庫。它能夠在運行期擴展 Java 類或者實現 Java 接口。固然這些實際的功能是 asm 所提供的,asm 又是什麼?它是 Java 字節碼操控框架,具體是什麼你們能夠上網查一查,畢竟咱們這裏所要討論的是 cglib。cglib 就是封裝了 asm,簡化了 asm 的操做,實現了在運行期動態生成新的 class 的壹個第三方類庫。可能你們還感受不到它的強大,如今就告訴你。實際上 cglib 爲 spring aop 提供了底層的一種實現;爲 hibernate 使用 cglib 動態生成 VO/PO(接口層對象)。 java
下面咱們將經過一個具體的事例來看一下 cglib,體驗一下 cglib。使用到的 Jar 包有 cglib-2.13.jar 和 asm-2.23.jar。以壹個實例簡單介紹下 cglib 的應用。 spring
咱們模擬一個虛擬的場景,模擬對錶的操做。壹開始咱們對錶提供了CRUD方法。咱們如今建立一個對 Table 操做的 DAO 類。源代碼以下: 框架
public class TableDAO { public void create(){ System.out.println("create() is running !"); } public void query(){ System.out.println("query() is running !"); } public void update(){ System.out.println("update() is running !"); } public void delete(){ System.out.println("delete() is running !"); } }OK,它就是一個 JavaBean,提供了 CRUD 方法的 JavaBean。下面咱們建立一個DAO工廠,用來生成DAO實例。
public class TableDAOFactory { private static TableDAO tDao = new TableDAO(); public static TableDAO getInstance(){ return tDao; } }接下來咱們建立客戶端,用來調用CRUD方法。
public class Client { public static void main(String[] args) { TableDAO tableDao = TableDAOFactory.getInstance(); doMethod(tableDao); } public static void doMethod(TableDAO dao){ dao.create(); dao.query(); dao.update(); dao.delete(); } }OK,完成了,CRUD方法徹底被調用了。固然這裏並無 cglib 的任何內容。問題不會這麼簡單的就結束,新的需求來臨了。
變化隨之而來,Boss告訴咱們這些方法不能開放給用戶,只有「張三」纔有權使用。怎麼辦,難道咱們要在每一個方法上面進行判斷嗎?好像這麼作也太那啥了吧,對了對了,Proxy 多是最好的解決辦法。jdk 的代理就能夠解決了。好了咱們來動手改造吧。等等,jdk 的代理須要實現接口,這樣,咱們的dao類須要改變了。既然不想改動dao 又要使用代理,咱們這就請出 cglib。咱們只需新增一個權限驗證的方法攔截器。 性能
public class AuthProxy implements MethodInterceptor { private String name ; //傳入用戶名稱 public AuthProxy(String name){ this.name = name; } public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { //用戶進行判斷 if(!"張三".equals(name)){ System.out.println("你沒有權限!"); return null; } return arg3.invokeSuper(arg0, arg2); } }固然不能忘了對咱們的dao工廠進行修改,咱們提供一個使用代理的實例生成方法。
public static TableDAO getAuthInstance(AuthProxy authProxy){ Enhancer en = new Enhancer(); //進行代理 en.setSuperclass(TableDAO.class); en.setCallback(authProxy); //生成代理實例 return (TableDAO)en.create(); }咱們這就能夠看看客戶端的實現了。添加了兩個方法用來驗證不一樣用戶的權限。
public static void haveAuth(){ TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("張三")); doMethod(tDao); } public static void haveNoAuth(){ TableDAO tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四")); doMethod(tDao); }OK,"張三"的正常執行,"李四"的沒有執行。
public class AuthProxyFilter implements CallbackFilter{ public int accept(Method arg0) { if(!"query".equalsIgnoreCase(arg0.getName())) return 0; return 1; } }OK,可能你們會對返回值 0 或者 1 感到困惑,用到的時候就會講解,固然下面就會用到了。
咱們在工廠中新增一個使用了過濾器的實例生成方法。 this
public static TableDAO getAuthInstanceByFilter(AuthProxy authProxy){ Enhancer en = new Enhancer(); en.setSuperclass(TableDAO.class); en.setCallbacks(new Callback[]{authProxy,NoOp.INSTANCE}); en.setCallbackFilter(new AuthProxyFilter()); return (TableDAO)en.create(); }
看到了嗎,setCallbacks() 中定義了所使用的攔截器,其中 NoOp.INSTANCE 是 CGlib 所提供的實際是一個沒有任何操做的攔截器,他們是有序的。必定要和 CallbackFilter 裏面的順序一致。明白了嗎?上面return返回的就是返回的順序。也就是說若是調用 query 方法就使用 NoOp.INSTANCE 進行攔截。
如今看一下客戶端代碼。 spa
public static void haveAuthByFilter(){ TableDAO tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("張三")); doMethod(tDao); tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四")); doMethod(tDao); }
OK,如今"李四"也可使用query方法了,其餘方法仍然沒有權限。固然這個代理的實現沒有任何侵入性,無需強制讓 dao 去實現接口。
hibernate