cglib 项目地址:https://github.com/cglib/cglib 。
和 Java自带的动态代理 ( Java 动态代理 )不同,cgilib 动态代理没有必须使用接口的限制。也就是,如果一个类没有实现任何接口,cglib 支持对其生成动态代理。当然,如果一个类实现了一些接口,cglib 也支持对其生成动态代理。cglib 的代理机制基于继承。
要使用 cglib,需要引入依赖。如果使用 gradle 构建项目,配置依赖如下:
compile group: 'cglib', name: 'cglib', version: '3.2.10'
入门
Hello 类是要被代理的类:
package demo01;
public class Hello {
public void hello() {
System.out.println("hello");
}
public void hi() {
System.out.println("hi");
}
}
方法执行的拦截器类,用于实现动态代理:
package demo01;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CustomInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.printf("发起调用. obj: %s, method: %s, proxy: %s\n",
obj.getClass().getCanonicalName(),
method.getName(),
proxy.getClass().getCanonicalName()
);
return proxy.invokeSuper(obj, args);
}
// 该函数用于生成代理
public static Object createProxy(Class cls) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new CustomInterceptor());
return enhancer.create();
}
}
测试代理效果:
package demo01;
public class Main {
public static void main(String[] args) {
Hello hello = (Hello) CustomInterceptor.createProxy(Hello.class);
hello.hello();
}
}
运行结果:
发起调用. obj: demo01.Hello$$EnhancerByCGLIB$$564008dc, method: hello, proxy: net.sf.cglib.proxy.MethodProxy
hello
MethodInterceptor 是方法级别的代理
上面的示例中,CustomInterceptor 继承自 MethodInterceptor 。MethodInterceptor 实现的是方法级别的代理。当被代理类进行自调用时,依然会执行代理逻辑。
在 Hello 类的 hello 方法中增加自调用:
public class Hello {
public void hello() {
System.out.println("hello");
hi(); // 调用 hi
}
public void hi() {
System.out.println("hi");
}
}
运行下面的测试代码:
public class Main {
public static void main(String[] args) {
Hello hello = (Hello) CustomInterceptor.createProxy(Hello.class);
hello.hello();
}
}
结果如下:
发起调用. obj: demo02.Hello$$EnhancerByCGLIB$$263b7947, method: hello, proxy: net.sf.cglib.proxy.MethodProxy
hello
发起调用. obj: demo02.Hello$$EnhancerByCGLIB$$263b7947, method: hi, proxy: net.sf.cglib.proxy.MethodProxy
hi
使用 InvocationHandler 构造类级别的代理
有时候,我们并不想自调用的时候走代理逻辑,那么,可以使用 InvocationHandler 构造类级别的代理。
Java本身的动态代理中也涉及一个类,名字也是 InvocationHandler 。不过它的全路径是 java.lang.reflect.InvocationHandler。 cglib 中的全路径是 net.sf.cglib.proxy.InvocationHandler。
我们看下如何使用:
package demo03;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
public class CustomInterceptor implements InvocationHandler {
private Object target;
public CustomInterceptor(Object target) {
this.target = target;
}
public static Object createProxy(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CustomInterceptor(target));
return enhancer.create();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf("发起调用. method: %s, proxy: %s\n",
method.getName(),
proxy.getClass().getCanonicalName()
);
return method.invoke(target, args);
}
}
假如被代理类代码是:
package demo03;
public class Hello {
public void hello() {
System.out.println("hello");
hi();
}
public void hi() {
System.out.println("hi");
}
}
测试代理效果:
package demo03;
public class Main {
public static void main(String[] args) {
Hello hello = (Hello) CustomInterceptor.createProxy(new Hello());
hello.hello();
}
}
运行结果如下:
发起调用. method: hello, proxy: demo03.Hello$$EnhancerByCGLIB$$8913a7da
hello
hi
可以看到,输出 hi 时,没有输出 CustomInterceptor 中那些额外内容。