CGlib概述:
cglib(
Code Generation Library
)是一個強大的,高性能,高質(zhì)量的Code生成類庫。它可以在運行期擴展Java類與實現(xiàn)Java接口。
cglib封裝了asm,可以在運行期動態(tài)生成新的class。
cglib用于AOP,jdk中的proxy必須基于接口,cglib卻沒有這個限制。
CGlib應(yīng)用:
以一個實例在簡單介紹下cglib的應(yīng)用。
我們模擬一個虛擬的場景,關(guān)于信息的管理。
1)原始需求是任何人可以操作信息的create,update,delete,query操作。
InfoManager.java
--封裝對信息的操作
???? // ?模擬查詢操作
???? public ? void ?query()?{
????????System.out.println( " query " );
????}
???? // ?模擬創(chuàng)建操作
???? public ? void ?create()?{
????????System.out.println( " create " );
????}
???? // ?模擬更新操作
???? public ? void ?update()?{
????????System.out.println( " update " );
????}
???? // ?模擬刪除操作
???? public ? void ?delete()?{
????????System.out.println( " delete " );
????}
}
?
InfoManagerFactory.java --工廠類
???? private ? static ?InfoManager?manger? = ? new ?InfoManager();
???? /**
?????*?創(chuàng)建原始的InfoManager
?????*?
?????*? @return
????? */
???? public ? static ?InfoManager?getInstance()?{
???????? return ?manger;
????}
}
?
client.java --供客戶端調(diào)用
???? public ? static ? void ?main(String[]?args)?{
????????Client?c? = ? new ?Client();
????????c.anyonecanManager();
????}
???? /**
?????*?模擬:沒有任何權(quán)限要求,任何人都可以操作
????? */
???? 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();
????}
???? /**
?????*?加一個分隔行,用于區(qū)分
????? */
???? private ? void ?separatorLine()?{
????????System.out.println( " ################################ " );
????}
}
至此,沒有涉及到cglib的內(nèi)容,因為需求太簡單了,但是接下來,需求發(fā)生了改變,要求:
2)只有一個叫“maurice”的用戶登錄,才允許對信息進行create,update,delete,query的操作。
怎么辦?難道在每個方法前,都加上一個權(quán)限判斷嗎?這樣重復(fù)邏輯太多了,于是乎想到了Proxy(代理模式),但是原先的InfoManager也沒有實現(xiàn)接口,不能采用jdk的proxy。那么cglib在這邊就要隆重登場。
一旦使用cgblig,只需要添加一個MethodInterceptor的類以及修改factory代碼就可以實現(xiàn)這個需求。
?
AuthProxy.java --權(quán)限校驗代理類
???? private ?String?name;? // ?會員登錄名
???? public ?AuthProxy(String?name)?{
???????? this .name? = ?name;
????}
???? /**
?????*?權(quán)限校驗,如果會員名為:maurice,則有權(quán)限做操作,否則提示沒有權(quán)限
????? */
????@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 --代碼變動如下:
???? /**
?????*?創(chuàng)建帶有權(quán)限檢驗的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 ? static ? void ?main(String[]?args)?{
????????Client?c? = ? new ?Client();
????????c.haveNoAuthManager();
????????c.haveAuthManager();
????}
???? /**
?????*?模擬:登錄會員沒有權(quán)限
????? */
???? 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();
????}
???? /**
?????*?模擬:登錄會員有權(quán)限
????? */
???? 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();
????}
???? /**
?????*?加一個分隔行,用于區(qū)分
????? */
???? private ? void ?separatorLine()?{
????????System.out.println( " ################################ " );
????}
}
執(zhí)行下代碼,發(fā)現(xiàn)這時client端中已經(jīng)加上了權(quán)限校驗。
到這里,參照上面的代碼,就可以使用cglib帶來的aop功能了。但是為了更多介紹下cglib的功能,模擬需求再次發(fā)生變化:
3)由于query功能用戶maurice才能使用,招來其他用戶的強烈的抱怨,所以權(quán)限再次變更,只有create,update,delete,才需要權(quán)限保護,query任何人都可以使用。
怎么辦?采用AuthProxy,使得InfoManager中的所有方法都被代理,加上了權(quán)限的判斷。當然,最容易想到的辦法,就是在 AuthProxy的intercept的方法中再做下判斷,如果代理的method是query,不需要權(quán)限驗證。這么做,可以,但是一旦邏輯比較復(fù)雜 的時候,intercept這個方法要做的事情會很多,邏輯會異常的復(fù)雜。
幸好,cglib還提供了CallbackFilter。使用CallbackFilter,可以明確表明,被代理的類(InfoManager)中不同的方法,被哪個攔截器(interceptor)攔截。
?
AuthProxyFilter.java
???? private ? static ? final ? int ?AUTH_NEED????? = ? 0 ;
???? private ? static ? final ? int ?AUTH_NOT_NEED? = ? 1 ;
???? /**
?????*?<pre>
?????*?選擇使用的proxy
?????*?如果調(diào)用query函數(shù),則使用第二個proxy
?????*?否則,使用第一個proxy
?????*?</pre>
????? */
????@Override
???? public ? int ?accept(Method?method)?{
???????? if ?( " query " .equals(method.getName()))?{
???????????? return ?AUTH_NOT_NEED;
????????}
???????? return ?AUTH_NEED;
????}
}
這段代碼什么意思?其中的accept方法的意思是說,如果代理的方法是query(),那么使用第二個攔截器去攔截,如果代理的方法不是 query(),那么使用第一個攔截器去攔截。所以我們只要再寫一個攔截器,不做權(quán)限校驗就行了。(其實,cglib中的NoOp.INSTANCE就是 一個空的攔截器,只要配置上這個就可以了。)
?
InfoManagerFactory.java --代碼修改如下:(配置不同的攔截器和filter)
???? /**
?????*?創(chuàng)建不同權(quán)限要求的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();
????}
}
記?。簊etCallbacks中的攔截器(interceptor)的順序,一定要和
CallbackFilter里面指定的順序一致??!切忌。
Client.java
???? public ? static ? void ?main(String[]?args)?{
????????Client?c? = ? new ?Client();
????????c.selectivityAuthManager();
????}
????
???? /**
?????*?模擬:沒有權(quán)限的會員,可以作查詢操作
????? */
???? 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();
????}
???? /**
?????*?加一個分隔行,用于區(qū)分
????? */
???? private ? void ?separatorLine()?{
????????System.out.println( " ################################ " );
????}
}
此時,對于query的權(quán)限校驗已經(jīng)被去掉了。
通過一個模擬需求,簡單介紹了cglib aop功能的使用。
CGlib應(yīng)用非常廣,在spring,hibernate等框架中,被大量的使用。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
