标签:
上一篇文章《设计模式--动态代理(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..."); } }
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,可以查看生成的代理类。
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://blog.csdn.net/zhangyingjie09/article/details/46291131