代理
JDK动态代理
// loader – the class loader to define the proxy class 类加载器
// interfaces – the list of interfaces for the proxy class to implement 类实现接口
// h – the invocation handler to dispatch method invocations to 调用方法前后执行的动作
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException { ... }
public interface InvocationHandler {
// return handler.invoke( proxy, method, args ) ;
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
CGLIB动态代理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
/**
* obj :被代理的对象(需要增强的对象)
* method :被拦截的方法(需要增强的方法)
* args :方法入参
* methodProxy :用于调用原始方法
*/
public interface MethodInterceptor extends Callback {
// 拦截被代理类中的方法
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
}
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
String path = "/tmp";
// 该设置用于输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}
两种代理方式的对比
JDK代理
- 大部分情况下效率比GCLIB代理高
- 只能代理实现了接口的类
CGLIB代理
- 可代理的方法更多,没有接口的局限性
- 不能代理声明为final的类和方法
代理失效的情况
- JDK代理
- 未在接口上的方法
- CALIB代理
- 声明为final的类或方法
- 不走代理的情况
- 类内部通过this调用