我们知道JDK动态代理只能代理实现了接口的类,没有实现接口的类是无法通过JDK来代理的。
Cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,这个子类覆盖目标类的方法并在其中实现方法的增强。因为采用了继承和重写,因此不能对final的类、final方法进行代理。
Cglib底层其实是借助了ASM这个非常强大的Java字节码生成框架,它可以在运行时对字节码进行修改或动态生成。
public class CglibTest {
public String say (String s) {
return "你好:" + s;
}
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法前.....");
methodProxy.invokeSuper(o, objects); //调用目标对象的方法
System.out.println("调用方法后.....");
return o;
}
intercept() 方法中有4个参数:
实现intercept()方法有点类似于实现JDK动态代理中InvocationHandler接口中的invoke()方法,都是在该方法中添加需要被代理的逻辑。
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy(); //MethodInterceptor的实现类
Enhancer enhancer = new Enhancer(); //借助Enhancer对象
enhancer.setSuperclass(CglibTarget.class); //目标对象字节码
enhancer.setCallback(proxy); //设置回调即MethodInterceptor的实现类
CglibTarget cglibTarget = (CglibTarget) enhancer.create(); //生成代理对象
cglibTarget.say("lebron"); //调用目标方法
}
输出:
调用方法前.....
你好:lebron
调用方法后.....
简单描述Cglib代理过程:
通过Cglib的Enhancer来指定要代理的目标对象(传入的是目标对象class对象)、实际处理代理逻辑的对象(MethodInterceptor实现类),最终通过调用create()方法得到代理对象。
当代理对象调用目标方法时,都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何代理逻辑,比如修改方法参数,加入日志功能、安全检查功能等;在intercept()方法中,通过调用MethodProxy.invokeSuper()方法,我们将调用转发给原始目标对象,在本例中也就是CglibTarget的具体方法。
这里只要增加相应方法的MethodInterceptor 的实现类以及实现一个回调过滤器CallbackFilter即可完成。
在目标对象中增加一个 record() 方法:
public class CglibTarget {
public void say (String s) {
System.out.println( "你好:" + s);
}
public void record (String s) {
System.out.println( "功能:" + s);
}
}
MethodInterceptor实现类:针对调用 record() 方法的拦截,目的是记录方法调用前后的时间
public class CglibProxy2 implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("当前时间: " + System.currentTimeMillis());
methodProxy.invokeSuper(o, objects); //调用目标对象的方法
System.out.println("运行结束时间: " + System.currentTimeMillis());
return o;
}
}
拦截过滤器CallbackFilter:CallbackFilter的accept()方法返回的数值表示的是Callback[]数组的索引,Callback[]数组中的元素就是定义好的MethodInterceptor实现类。
public class ProxyFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if ("say".equals(method.getName())) {
return 0;
}
return 1;
}
}
如果调用的是 say()方法,那么返回0,表示采用Callback[0]也就是第一个MethodInterceptor实现类来拦截 say()方法;
main方法测试:
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy(); //MethodInterceptor的实现类1
CglibProxy2 proxy2 = new CglibProxy2(); //MethodInterceptor的实现类2
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibTarget.class); //目标对象字节码
enhancer.setCallbacks(new Callback[]{proxy, proxy2}); //设置回调即MethodInterceptor的实现类
enhancer.setCallbackFilter(new ProxyFilter()); //设置方法顺序?
CglibTarget cglibTarget = (CglibTarget) enhancer.create(); //生成代理对象
cglibTarget.say("lebron");
cglibTarget.record("记录时间");
}
输出:
调用方法前.....
你好:lebron
调用方法后.....
当前时间: 1532182370942
功能:记录时间
运行结束时间: 1532182370942
可见,针对say() 和 record() 这两个不同的方法实现了不同的代理逻辑。
针对不同的方法,可以定义不同的MethodInterceptor,来实现不同的代理逻辑。