代理为要控制访问的类提供了一种可行的途径,他为目标类引入一个中间层,JDK1.3后也有动态代理,不过性能不是很好,1.6有所加强。
CGLIB是一个强大的代码生成包,在ASM上建立,在一些开源工具中经常可以看到他的身影,比如hibernate,spring。
CGLIB底层通过字节码处理框架ASM来将字节码生成新的类,在spring AOP中不强制使用CGLIB,默认是JDK动态代理。
CGLIB 包情况:
net.sf.cglib.core:底层字节码处理类,大部分与ASM有关。
net.sf.cglib.transform:编译期或运行期和类文件的转换
net.sf.cglib.proxy:实现创建代理和方法拦截器的类
net.sf.cglib.reflect:实现快速放射
net.sf.cglib.util:工具包
net.sf.cglib.beans:javabean相关工具类
通过CGLIB创建动态代理,本质上,他是动态的生成目标类的子类,覆盖目标类所有不是final的方法,并给他们设置好callback,因此,原有类的每个方法调用就会变成自定义的拦截方法。
创建动态代理时通常要用到如下api:net.sf.cglib.proxy.Callback这个接口,他是很关键的一个接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调借口都要继承这个接口
如:public interface MethodInterceptor
extends Callback
{
/**
* All generated proxied methods call this method instead of the original method.
* The original method may either be invoked by normal reflection using the Method object,
* or by using the MethodProxy (faster).
* @param obj "this", the enhanced object
* @param method intercepted Method
* @param args argument array; primitive types are wrapped
* @param proxy used to invoke super (non-intercepted method); may be called
* as many times as needed
* @throws Throwable any exception may be thrown; if so, super method will not be invoked
* @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
* @see MethodProxy
*/
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
}
这个是基与方法的回调,第一个参数是代理对象,第二个是被拦截的方法对象,第三个是方法参数,第四个是方法的代理对象。
public class MyClass {
public void method1() {
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
}
拦截器:
public class MethodInterceptImpl implements MethodInterceptor {
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println(arg1.getName()+"--intercept");
arg3.invokeSuper(arg0, arg2);// 这里其实也可以用原来的方法对象来执行,但是性能上不如cglib的方法代理类
return null;
}
public class MainTest {
public static void main(String[] args) {
simpleTest();
}
private static void simpleTest() {
Enhancer en = new Enhancer();
en.setCallback(new MethodInterceptImpl());
en.setSuperclass(MyClass.class);
MyClass m = (MyClass) en.create();
m.method1();
m.method2();
}
结果:method1--intercept
method1
method2--intercept
method2
现实项目中可能存在某些需求,比如method1需要拦截,而method2不需要拦截。那我们可以对callback做下选择,使用net.sf.cglib.proxy.CallbackFilter做一些过滤。
public class MethodFilterImpl implements CallbackFilter {
private final static int execute = 0;
private final static int unexecute = 1;
public int accept(Method method) {
String methodName = method.getName();
if("method1".equals(methodName)){
return execute;
}
return unexecute;
}
}
调用的时候需要给callback设置好索引位置,因为accept的返回值就是callbacks数组的索引位置。
private static void filterTest() {
Enhancer en = new Enhancer();
Callback[] callbacks = new Callback[] { new MethodInterceptImpl(),
NoOp.INSTANCE };//这里拦截器的索引位置要与filter里的设置一致
en.setCallbacks(callbacks);
en.setSuperclass(MyClass.class);
en.setCallbackFilter(new MethodFilterImpl());
MyClass m = (MyClass) en.create();
m.method1();
m.method2();
}
这里callbacks[1]这个位置使用了NoOp这个回调接口
public interface NoOp extends Callback
{
/**
* A thread-safe singleton instance of the <code>NoOp</code> callback.
*/
public static final NoOp INSTANCE = new NoOp() { };
}
这个callback其实就是直接把任务委派给这个方法在父类中的实现,其实也等同于没做什么额外的事情
执行结果:method1--intercept
method1
method2
method2 并未被MethodInterceptImpl拦截
}