一、什么是CGLIB?
总的来说,无论是cglib、jdk动态代理又或者是aop面向切面编程,都运用到了一个最重要的设计模式--代理模式!万变不离其终,学好代理模式,打遍天下无敌手!
cglib就是一个字节码生成
和转换
的库嘛!这倒是不难理解,它主要被AOP,测试,数据访问框架用来生成动态代理对象
和拦截字段访问
。
今天我们就来说说cglib在代理方面的应用!
二、CGLIB源码粗略解读!
首先我们来看看cglib源码的包结构:
从cglib核心包中可以看到有个proxy
的包,我们一起去探个究竟!展开proxy
可以发现:
在该包中的Enhancer
类和MethodInterceptor
接口是整个包的核心所在!Enhancer
就是“增强”的意思嘛!主要用于生成动态子类
以启用方法拦截,什么意思?这样子讲!cglib类代理的基本思想就是对被代理类生成一个新的类(proxy
),该类是继承自被代理类的,并对被代理类方法执行前后执行一些操作,这些操作的通常就是一些回调操作,可以是MethodInterceptor
,LazyLoader
,CallbackFilter
,其中MethodInterceptor
是最常用的。
所有被Enhancer
关联的对象默认都是实现Factory
接口的,该接口提供了一组可以设置对象回调类型的方法,你可以通过调用setUseFactory(false)
取消此特性!
需要注意的是,cglib是无法代理final
修饰的方法的,因为这是java语言规范决定的!
MethodInterceptor
是一个提供环绕通知
的通用回调接口!Aop中有这样的术语,那就是前置通知
,后置通知
,环绕通知
,非常好理解,就是一个在方法执行前的通知,一个方法执行后的通知,另外一个就是方法执行前后都通知。
该接口只有一个intercept()
方法:
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
所有对被代理类方法的执行都会跳转到这个方法上面来,而原来的方法则通过反射得到的Method
对象或者MethodProxy
对象进行调用。
三、老规矩,来个栗子一起团圆!
代码语言:javascript复制import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class Student {
private String name = "zhangsan";
public String getStuName() {
return name;
}
}
public class CglibMethodInterceptTest {
public static void main(String[] args) {
//创建一个Enhancer对象
Enhancer enchaner = new Enhancer();
//设置被代理的类
enchaner.setSuperclass(Student.class);
//创建一个回调接口
Callback interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.err.println("原方法名是 : " method.getName());
System.err.println("原方法声明的类为 " method.getDeclaringClass());
System.err.println("我是 " (String) proxy.invokeSuper(obj, args));
System.err.println("我调用结束了");
return null;
}
};
enchaner.setCallback(interceptor);
Student student = (Student) enchaner.create();
student.getStuName();
}
}
输出的结果为:
代码语言:javascript复制原方法名是 : getStuName
原方法声明的类为 class wokao666.test.Student
我是 zhangsan
我调用结束了
过滤器的使用
package wokao666.test;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
class Student {
private String name = "zhangsan";
private String rename = "rename";
public String getStuName() {
return name;
}
public String getRename() {
return rename;
}
}
public class CglibMethodInterceptTest {
public static void main(String[] args) {
//创建一个Enhancer对象
Enhancer enchaner = new Enhancer();
//设置被代理的类
enchaner.setSuperclass(Student.class);
//创建一个回调接口
Callback interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.err.println("原方法名是 : " method.getName());
System.err.println("原方法声明的类为 " method.getDeclaringClass());
System.err.println("我是 " (String) proxy.invokeSuper(obj, args));
System.err.println("我调用结束了");
return proxy.invokeSuper(obj, args);
}
};
CallbackFilter callbackFilter = new CallbackFilter() {
@Override
public int accept(Method method) {
int flag = 0;
if ("getStuName".equals(method.getName())) {
System.err.println("我将此方法过滤掉了,不对该方法进行拦截");
return 1;
}
return 0;
}
};
Callback[] callbacks = new Callback[] { interceptor, NoOp.INSTANCE };
enchaner.setCallbackFilter(callbackFilter);
enchaner.setCallbacks(callbacks);
Student student = (Student) enchaner.create();
System.err.println(student.getStuName());
System.err.println(student.getRename());
}
}
代码语言:javascript复制我将此方法过滤掉了,不对该方法进行拦截
zhangsan
原方法名是 : getRename
原方法声明的类为 class wokao666.test.Student
我是 rename
我调用结束了
rename
NoOp.INSTANCE
:这个NoOp
表示no operator
,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。
getStuName
对应的CallbackFilter中定义的索引1,在Callback[]
数组中使用的过滤为NoOp
,因此直接执行了被代理方法。
getRename
对应CallbackFilter中定义的索引0,在Callback[]
数组中使用的过滤为interceptor
,因此执行了方法拦截器进行拦截。
我写的只是一点皮毛,建议大家在此基础上多动手,结合源代码多写写一些例子,写多了,懂得就多了!