- 浏览: 216831 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
zi_wu_xian:
顶5楼,POI操作word和excel还是太复杂了,并且针对d ...
使用POI操作Excel和Word -
贝塔ZQ:
poi操作word、excel代码好多啊,用插件试试吧,网上不 ...
使用POI操作Excel和Word -
wap816:
@CacheEvict(value = ...
SpringEL详解及应用 -
string2020:
List<Map<String,Map<St ...
开源工具 — Apache Commons Collections -
uniqueX:
mark!
并发编程 — 判断线程安全
AOP系列文章:
Spring AOP:http://ray-yui.iteye.com/blog/2024759
CGLIB:http://ray-yui.iteye.com/blog/2026426
Javassist:http://ray-yui.iteye.com/blog/2029261
什么是CGLIB?
CGLIB是一个强大的高性能的代码生成包.它广泛的被许多AOP的框架使用,例如Spring AOP.诸如EasyMock和JMock等通过模仿对象来测试java代码的包都使用CGLIB.他们都通过使用CGLIB来为那些没有实现接口的类创建代理,流行ORM框架Hibernate亦使用CGLIB来实现延迟加载和单端映射(新版本Hibernate已直接依赖更底层的ASM),CGLIB底层通过一个小而快的字节码处理框架ASM,来转换字节码并生成新的类.ASM是低級的字节码生成工具,使用ASM已经近乎接近使用Java bytecode编程,而使用CGLIB更像是对ASM进行的高级化封装.
为什么要使用CGLIB?
JDK内置的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的类必须实现一个或多个接口.注意必须是接口,如果想代理没有实现接口的类,JDK内置的动态代理就显得非常无力,此时CGLIB就显出了它的魅力,而且CGLIB因為使用直接生成字节码的方式,效率更高
CGLIB使用:
public class TestMain { // 第一种写法,使用Enhancer静态create方法 @Test public void testCGLIBProxy01() { /* * create有多种重载方式,此重载第一个参数为超类(本类)的类型, * 若然需要动态代理的类没有实现接口,就需要填写第一个参数, * 第二个参数为Class类型的数组,当动态代理的类有实现接口, * 可以选择性填写第二个参数,否则为null */ RayTest test = (RayTest) Enhancer.create(RayTest.class, null, new MethodInterceptor() { // 真实主题 RayTest test = new RayTest(); @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { // 动态代理增加的logic String before = "before "; // 使用MethodProxy调用效率更高 Object str = arg3.invoke(test, args); String after = " after"; return before + str + after; } }); Assert.assertEquals("before RayTest after", test.execute()); } // 第二种写法,创建Enhancer对象 @Test public void testCGLIBProxy2() { // 创建Enhancer类 Enhancer enhancer = new Enhancer(); // 当类没有实现接口而又需要动态代理,使用setSuperclass enhancer.setSuperclass(RayTest.class); // 当类实现了接口需要动态代理,使用setInterface enhancer.setInterfaces(new Class[] {}); enhancer.setCallback(new MethodInterceptor() { // 真实主题 RayTest test = new RayTest(); @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { // 动态代理增加的logic String before = "before "; // 使用MethodProxy调用效率更 Object str = arg3.invoke(test, args); String after = " after"; return before + str + after; } }); Assert.assertEquals("before RayTest after", enhancer.create()); } }
通过上面的代码可以看出.真正处理代理业务逻辑也就是JDK动态代理中InvocationHandler中invoke方法的是使用enhancer.setCallback传递Callback接口实现来进行.上面例子中我们使用MethodInterceptor,MethodInterceptor能满足所有拦截的业务需求,但一些已经普遍存在的动态代理使用方式,例如使用动态代理实现延迟加载,CGLIB为我们提供了更方便和简化的实现
public class TestMain { private Enhancer enhancer; @Before public void init() { this.enhancer = new Enhancer(); enhancer.setSuperclass(RayTest.class); } @Test public void testCGLIBUseSuperClass() { // NoOp实现类会使用默认的父类实现,没增加任何logic enhancer.setCallback(NoOp.INSTANCE); RayTest test = (RayTest) enhancer.create(); Assert.assertNotNull(test); } @Test public void testCGLIBLazyObject() { //实现LazyLoader接口,在创建对象时可以增加业务logic和创建对象的子类等 enhancer.setCallback(new LazyLoader() { @Override public Object loadObject() throws Exception { final RayTest lazyTest = new RayTest(); return lazyTest; } }); RayTest test = (RayTest) enhancer.create(); Assert.assertNotNull(test); } }
由于CGLIB可以不需要实现接口来实现动态代理,其原理是通过字节码生成类的一个子类来完成的,那就有可能出现需要动态代理对象不存在一个无参构造函数,那么CGLIB在生成子类并实例化时将会产生错误
public class TestMain { /* * 我們假设RayTest类不存在默认构造函数, * 只提供需要传入 String和Integer作为参数的构造函数 */ private Enhancer enhancer; @Before public void init() { this.enhancer = new Enhancer(); enhancer.setSuperclass(RayTest.class); } public void testNotExistDefaultConstructor() { enhancer.setCallback(NoOp.INSTANCE); // 可以使用create的重载方式,参数1是构造函数参数类型,参数2是值 RayTest test = (RayTest) enhancer.create(new Class[] { String.class, Integer.class }, new Object[] { "Hello World", 100 }); Assert.assertNotNull(test); } }
在我们真实开发当中,在使用动态代理进行方法请求拦截时,可能会需要判断调用的方法然后决定拦截的逻辑,也就是同一个代理类在调用不同的方法时拦截的逻辑都不相同,CGLIB提供了CallbackFilter来帮助我们实现这一功能
public class TestMain { private Enhancer enhancer; @Before public void init() { this.enhancer = new Enhancer(); enhancer.setSuperclass(RayTest.class); } @Test public void testCGLIBCallbackFilter() { // 创建callback1 Callback callback1 = new MethodInterceptor() { // 真是主题类 RayTest test = new RayTest(); @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { String before = "callback1 before "; Object str = proxy.invoke(test, args); String after = " callback1 after"; return before + str + after; } }; // 创建callback2 Callback callback2 = new MethodInterceptor() { // 真是主题类 RayTest test = new RayTest(); @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { String before = "callback2 before "; Object str = proxy.invoke(test, args); String after = " callback2 after"; return before + str + after; } }; // 使用setCallbacks设置多个Callback enhancer.setCallbacks(new Callback[] { callback1, callback2 }); enhancer.setCallbackFilter(new CallbackFilter() { static final int EXECUTE_METHOD = 0; static final int OTHER_METHOD = 1; /* * accept需要返回一個int类型, * 该int类型为上文中setCallbacks设置的多个 * Callback处理逻辑的数组的下标,上文中设置了两个Callback, * 分别为callback1和callback2 */ @Override public int accept(Method method) { /* * Method参数代表代理类的执行方法, * 以下logic为 判断执行方法名称是否为execute, * 是则执行callback1,也就是数组下标为0的逻辑, * 否则执行Other逻辑 */ if ("execute".equals(method.getName())) return EXECUTE_METHOD; else return OTHER_METHOD; } }); RayTest test = (RayTest) enhancer.create(); String executeResult = test.execute(); Assert.assertEquals("callback1 before execute callback1 after", executeResult); String otherResult = test.action(); Assert.assertEquals("callback2 before action callback2 after", otherResult); } }
总结:在传统使用JDK动态代理时,会受限于必须实现接口而带来不便,若然该类是自己编写的话还可以抽象出多一层接口,若然该类是别人编写好并且已经正在生产使用,那就没有任何改动的理由,CGLIB帮助我们解决了没实现接口的继承问题,而且使用简单,提供了更多的功能例如CallbackFilter,这些都是JDK动态代理所没有的,而且效率也要高于JDK动态代理
发表评论
-
并发编程 — 实现线程安全
2015-08-12 09:03 2263并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 优化小技巧
2015-08-10 23:54 0并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 判断线程安全
2015-08-05 10:11 5461并发编程系列文章: ... -
并发编程 — volatile
2015-07-30 10:11 2146并发编程系列文章: 初解线程池:http://r ... -
数据库储存不确定实体
2014-07-08 09:52 2228相信在项目开发当中都曾经遇到过,有某些要储蓄到数 ... -
同步操作降低效率解惑
2014-06-30 10:20 3247相信在读者刚接触Java的时候,都曾经学习到线程 ... -
并发编程 — 并发数据结构
2014-06-24 09:58 5508并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 并发数据类型
2014-06-16 10:03 5401并发编程系列文章: 初解线程池:http://r ... -
并发编程 — 详解线程池
2014-06-03 09:51 5964本文章需要对JDK5 Executor框架有所了解,请读者先 ... -
并发编程 — 初解线程池
2014-05-28 09:57 7495并发编程系列文章: 初解线程池:http://r ... -
线程池详解
2014-05-26 18:20 0本文章需要对JDK5 Executor框架有所了 ... -
高级字节码生成工具 — Javassist
2014-03-11 09:57 6356AOP系列文章: Spring AOP:http ... -
实现AOP — Spring AOP
2014-03-03 10:02 4213AOP系列文章: Spring AOP:http ... -
cglib
2014-01-11 19:11 0什么是CGLIB? CGLIB是一个强大的高性能 ... -
Java高质量代码之 — 杂
2013-09-16 09:53 4695前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 异常
2013-09-09 09:35 6649前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 泛型与反射
2013-08-29 09:36 18018前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 枚举与注解
2013-08-27 09:59 15722前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 数组与集合(2)
2013-08-23 17:24 2847前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ... -
Java高质量代码之 — 数组与集合(1)
2013-08-21 12:24 7211前言:由于上一个星期工作繁忙,利用上下班和晚上睡前空余的时间 ...
相关推荐
Spring AOP实现方法之一:CGLIB 实现AOP功能
使用JDK中的Proxy技术实现AOP功能与使用CGLIB实现AOP功能
AOP、CGLIB
AOP-CGLIB学习-实现简单的注解权限系统
基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)...
如果想使用CGLIB的技术来生成代理对象,那么需要引入CGLIB的开发的jar包,在Spring框架核心包中已经引入了CGLIB的开发包了。所以直接引入Spring核心开发包即可!
JavaEE CGLIB字节码增强方式实现AOP编程
Spring-AOP-利用java中的动态代理和Spring的拦截器做到AOP
详细介绍了AOP的核心功能(拦截功能)在底层是如何实现的;介绍了两种实现AOP的动态代理:jdk动态代理和cglib动态代理,并详细描述了它们在代码层面的实现。附有必须的cglib.jar和asm.jar
spring aop 编程,cglib ,切面编程
AOP之JDK动态代理和CGLib动态代理 ,具体效果和过程看博文 http://blog.csdn.net/evankaka/article/details/45195383
静态代理--不适合企业开发,适合初学者理解代理。 jdk动态代理--适合企业级开发,但是它要求必须面向接口编程,假如目标类没有实现接口...spring 的AOP功能中 会根据目标类是否实现了接口来判断使用 jdk Proxy还是cglib
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 如何强制使用CGLIB实现AOP? * 添加CGLIB库,SPRING_HOME/...
Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现.doc
cglib实现动态代理所依赖的jar包 在学习spring中会用到
aop的四种实现方式代码示例,包括javassist cglib instrument dynamicproxy四种,里面都有注释。
SpringMVC精品资源--手写Spring,支持ioc(三级缓存)、aop(cglib)、内嵌tomcat
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现. Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的...
实现MethodInterceptor简单的aop 分别用cglib和反射实现了一下
通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。 二、CGLIB原理 CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。...