在前两篇的JDK动态代理中,它是通过Proxy类和实现InvocationHandler接口实现的。但是此方式最大的缺点是:要求被代理的目标类必须实现一个接口,而且只能对接口中的方法实现代理。因为最终生成的代理类是继承了Proxy类以及实现了目标类的接口。
如果被代理的目标类没有实现接口,JDK就无法完成代理。这时,可以采用CGLib动态代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。CGLib在运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。
拦截器:实现MethodInterceptor接口的类,在intercept方法中实现对代理目标类的方法拦截。
Enhancer类,来生成代理类。
CGLib动态代理实现:
先看如何实现:
目标类(被委托类)
package com.blog.cglibproxy;
/**
* @Description:
* @Author: Jingzeng Wang
* @Date: Created in 16:01 2017/6/27.
*/
public class UserDao {
/**
* 目标类的add方法
*/
public void add() {
System.out.println("目标类的添加方法!!");
}
/**
* 目标类的delete方法
*/
public void delete() {
System.out.println("目标类的删除方法!!");
}
}
代理逻辑,实现了MethodInterceptor 的intercept()方法:
package com.blog.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Description: 代理逻辑
* @Author: Jingzeng Wang
* @Date: Created in 17:12 2017/6/27.
*/
public class MyInterceptor implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//设置目标类
enhancer.setSuperclass(clazz);
//设置拦截实现类
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//横切逻辑
System.out.println("-------------------before-----------------");
//委托类方法
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("-------------------after------------------");
return result;
}
}
测试类:
package com.blog.cglibproxy;
/**
* @Description:
* @Author: Jingzeng Wang
* @Date: Created in 17:19 2017/6/27.
*/
public class Test {
public static void main(String[] args) {
MyInterceptor myInterceptor = new MyInterceptor();
UserDao proxy = (UserDao) myInterceptor.getProxy(UserDao.class);
proxy.add();
proxy.delete();
}
}
其结果为:
-------------------before-----------------
目标类的添加方法!!
-------------------after------------------
-------------------before-----------------
目标类的删除方法!!
-------------------after------------------
这就实现了对目标类的代理。生成的代理类是直接操作字节码继承了目标类。
CGLib动态代理与JDK动态代理的区别
CGLib主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态