码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式--动态代理(CGLIB)

时间:2015-05-31 21:44:33      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:


    上一篇文章《设计模式--动态代理(JDK)》已经写了JDK中动态代理的应用,这篇文章将介绍动态代理在CGLIB中应用。,从上篇文章中我们知道使用JDK动态代理是有一定限制。就是被代理类必须至少实现一个接口,因为JDK为我们生成的动态代理也是实现这个接口的。所以如果没有接口,JDK基本就歇菜了。CGLIB正好弥补了JDK的这个缺陷,他的被代理类是无需实现接口,因为它的实现机制是继承被代理类,从而创建一个代理对象(继承被代理对象)的。

     CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。将它的jar包引入到我们的程序就可以使用了。需要注意的是CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。所以cglib包中必须包含asm,否则会报错可以选择其他的CGLIB版本,比如cglib-nodep,它里面就含有asm包。

    在网上看了好多例子都说CGLIB运用了回调,虽然知道他们讲了什么,但是不明白为什么调用代理的方法就直接跳转到AuthProxy中的intercept方法中。网上总是说当调用代理对象的方法的时候,会自动调用intercept方法,但是WHY,就算把生成的代理反编译了,迷迷糊糊看不懂啊。然后化整为零从回调方法开始一个个击破,最后画出了相同的类图。现在对CGLIB的回调才稍微明白点了。


技术分享

下面写一个例子,也是在网上看到的,但是个人感觉很不错,在这里和大家分享。


1 代理类对表的各类操作

package com.tgb.cglibTable;
public class TableDao {
	public void create(){
        System.out.println("create() is running...");
    }
    public void delete(){
        System.out.println("delete() is running...");
    }
    public void update(){
        System.out.println("update() is running...");
    }
    public void query(){
        System.out.println("query() is running...");
    }

}


2生成代理类

package com.tgb.cglibTable;
import net.sf.cglib.proxy.Enhancer;
public class TableDAOFactory {
	private static TableDao tDao = new TableDao();  
    public static TableDao getInstance(){  
        return tDao;  
    }  
    public static TableDao getAuthInstance(AuthProxy authProxy){  
        Enhancer en = new Enhancer();  //Enhancer用来生成一个原有类的子类(代理类)
        //进行代理  
        en.setSuperclass(TableDao.class); 
        //设置织入逻辑
        en.setCallback(authProxy); //注册回调函数 
        //生成代理实例  
        return (TableDao)en.create();         
    } 
}

Enhancer是CGLIB的核心包,它是生成代理类的工具。在生成代理类的同时根据我们的参数对代理类进行设置,比如setSuperclass方法就是调用Enhancer的方法让生成的代理对象继承TabbleDao(被代理类)。setCallback就是设置回调。最后create方法,生成最后的代理类。如果想查看的生成的代理可以根据4中客户端中代码“System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"F:\\class");”获取,通过反编译工具jd-gui,可以查看生成的代理类。


3 定义拦截类
package com.tgb.cglibTable;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class AuthProxy implements MethodInterceptor {
	private String userName;
    AuthProxy(String userName){
        this.userName = userName;
    }
    //实现MethodInterceptor接口的intercept方法
    public Object intercept(Object arg0, Method arg1, Object[] arg2,
            MethodProxy arg3) throws Throwable {
        //权限判断
        if(!"张三".equals(userName)){
            System.out.println("你没有权限!");
            return null;
        }
        return arg3.invokeSuper(arg0, arg2);//把方法封装成了一个对象,然后回调父类(代理类中对应的方法)
    }

}
在用CGLIB生成的代理类中,当调用代理类中的方法时,会调用intercept方法。因为在生成的代理类中(create、delete、update、query)的方法都会调用intercept,在intercept方法我们就可以增加我们想要添加的各种操作。最后的invokeSuper使用反射机制回调父类相应的方法。

4 客户端调用

package com.tgb.cglibTable;

import net.sf.cglib.core.DebuggingClassWriter;

public class Client {
	 public static void main(String[] args) {
	 //将新生成的所有类存放到"F:\class",为了看生成的代理类,用反编译工具编译后可以看具体生成的代理类
	   System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"F:\\class");
       haveAuth(); 
       //haveNoAuth();
       //
   }  
	 //执行代理的增删改查
   public static void doMethod(TableDao dao){  
       dao.create();  
       dao.query();  
       dao.update();  
       dao.delete();  
   }  
   //模拟有权限
   public static void haveAuth(){  
       TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("张三"));  
       doMethod(tDao);  
   }  
   //模拟无权限
   public static void haveNoAuth(){  
       TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四"));  
       doMethod(tDao);  
   }
   
}


5 总结:

             (1)CGLIB的使用网上虽然有很多,但是却没有说为什么要这样写。所以看源码是很有必要的,但是哎。

     (2)问题较多无法解决的时候,需要从简单处入手,各个击破。


推荐链接:http://www.cnblogs.com/liuling/archive/2013/05/21/CGlib-AOP.html


设计模式--动态代理(CGLIB)

标签:

原文地址:http://blog.csdn.net/zhangyingjie09/article/details/46291131

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!