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
Java代碼 spring
- 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實例。 框架
Java代碼 性能
- public class TableDAOFactory {
- private static TableDAO tDao = new TableDAO();
- public static TableDAO getInstance(){
- return tDao;
- }
- }
接下來咱們建立客戶端,用來調用CRUD方法。 this
Java代碼 hibernate
- 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的任何內容。問題不會這麼簡單的就結束,新的需求來臨了。
2. 變化隨之而來,Boss告訴咱們這些方法不能開放給用戶,只有「張三」纔有權使用。阿~!怎麼辦,難道咱們要在每一個方法上面進行判斷嗎?
好像這麼作也太那啥了吧,對了對了Proxy多是最好的解決辦法。jdk的代理就能夠解決了。 好了咱們來動手改造吧。等等jdk的代理須要實現接口,這樣,
咱們的dao類須要改變了。既然不想改動dao又要使用代理,咱們這就請出CGlib。
咱們只需新增一個權限驗證的方法攔截器。 代理
Java代碼 對象
- 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工廠進行修改,咱們提供一個使用代理的實例生成方法 接口
Java代碼 get
- public static TableDAO getAuthInstance(AuthProxy authProxy){
- Enhancer en = new Enhancer();
- //進行代理
- en.setSuperclass(TableDAO.class);
- en.setCallback(authProxy);
- //生成代理實例
- return (TableDAO)en.create();
- }
咱們這就能夠看看客戶端的實現了。添加了兩個方法用來驗證不一樣用戶的權限。
Java代碼
- 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,"張三"的正常執行,"李四"的沒有執行。
看到了嗎?簡單的aop就這樣實現了
難道就這樣結束了麼?
3. Boss又來訓話了,不行不行,如今除了"張三"其餘人都用不了了,如今不能夠這樣。他們都來向我反映了,必須使用開放查詢功能。
哈哈,如今可難不倒咱們了,由於咱們使用了CGlib。固然最簡單的方式是去修改咱們的方法攔截器,不過這樣會使邏輯變得複雜,且
不利於維護。還好CGlib給咱們提供了方法過濾器(CallbackFilter),CallbackFilte能夠明確代表,被代理的類中不一樣的方法,
被哪一個攔截器所攔截。下面咱們就來作個過濾器用來過濾query方法。
Java代碼
- public class AuthProxyFilter implements CallbackFilter{
- public int accept(Method arg0) {
- if(!"query".equalsIgnoreCase(arg0.getName()))
- return 0;
- return 1;
- }
-
- }
OK,可能你們會對return 0 or 1感到困惑,用到的時候就會講解,固然下面就會用到了。
咱們在工場中新增一個使用了過濾器的實例生成方法。
Java代碼
- 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進行攔截。
如今看一下客戶端代碼。
Java代碼
- public static void haveAuthByFilter(){
- TableDAO tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("張三"));
- doMethod(tDao);
-
- tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四"));
- doMethod(tDao);
- }
ok,如今"李四"也可使用query方法了,其餘方法仍然沒有權限。 哈哈,固然這個代理的實現沒有任何侵入性,無需強制讓dao去實現接口。