简述
在上一篇博客中,我们仔细地分析了Java原生代理的实现机制,得出了如下结论
- 代理的类动态生成的。也就是说,在程序运行时创建类的字节码,并且动态加载到JVM中
- Java原生代理实际上是创造了一个实现了所有给定接口的类,并在调用接口的方法的时候使用反射达到代理效果
基于以上两点,我们能得出结论,如果要使用Java原生代理的话,就必须将类的每一个方法都写在接口里面再进行实现。而Cglib的出现,就解决了这个问题。在Cglib Github主页上我们能看到如此描述
Cglib(Code Generation Library) 能够提供生成和转换Java字节码的API,它被广泛运用在AOP,测试,数据处理以及生成动态代理和方法拦截的框架中。
接下来,我们看一下Cglib是如何工作的。
Cglib Proxy 示例
对于Cglib的代理对象,与Java原生代理对象相同,它们都需要生成一个代理类对代理对象进行持有,同时必须在生成这个代理类的时候,将一个回调方法处理类作为参数传入构造函数中。这样,当代理类的任意方法被调用的时候,Java原生代理会调用InvocationHandler
中的invoke
方法,而Cglib代理则会调用MethodInterceptor
中的intercept
方法。
仍然以前面博客中的UserDao
以及UserDaoImpl
为例进行代码示例。
SimpleMethodInterceptor.java
package com.study.cglib.learning;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SimpleMethodInterceptor implements MethodInterceptor{
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("proxy control!");
//注意,如果使用invoke方法,并且参数也为代理类,则会循环进入此拦截方法从而导致爆栈
//invokeSuper即为调用原生的方法
return proxy.invokeSuper(obj, args);
}
public Object createProxy(Class<?> clazz, Class<?>[] interfaces) {
Enhancer enhancer = new Enhancer();
//设置需要代理的类
enhancer.setSuperclass(clazz);
//设置需要代理的接口
enhancer.setInterfaces(interfaces);
//设置处理方法的回调函数
enhancer.setCallback(this);
//设置回掉函数的过滤方法
enhancer.setCallbackFilter(new SimpleCallBackfilter());
return enhancer.create();
}
}
SimpleCallBackfilter.java
public class SimpleCallBackfilter implements CallbackFilter{
@Override
public int accept(Method method) {
System.out.println("filtering!");
return 0;
}
}
我们可以为代理类设置多个回调方法(将回调类以数组形式传入setCallBacks方法中),然后再设置callBackFilter,callBackFilter返回的整型代表着第几个回调类的拦截方法将会被调用。
App.java
package com.study.cglib.learning;
public class App
{
public static void main( String[] args )
{
SimpleMethodInterceptor cgProxy = new SimpleMethodInterceptor();
UserDao userDao = (UserDao) cgProxy.createProxy(UserDaoImpl.class, null);
userDao.queryName();
//输出 : filtering!
// filtering!
// filtering!
// filtering!
// filtering!
// filtering!
// proxy control!
// getUserName
}
}
浅析Cglib生成代理类的方式
Enhancer.class
通过继承AbstractClassGenerator
,并且实现了generateClass
来进行代理类的字节码动态生成,其方式和过程与Java原生代理类似,找到所有声明的方法,构建构造函数,构建代理函数,最后根据内存中生成的所有函数,拼凑成字节码。唯一不同的是,Cglib**直接继承**委托类。而CallBackFilter实际上也是在生成函数的时候生效的,如下所示。
Enhancer.emitMethods