jdk动态代理与cglib动态代理
最近在用java实现redis,在使用动态代理时遇到了一点问题,即使用jdk动态代理(Invocationhandler)时,如果代理对象是一个接口的实现类,那么此时动态代理获取到的method对象是接口中的,而不是实现类的,现象是:我在实现类中对接口方法上新增了注解,但是此刻method反射获取不到注解信息,于是大概整理了一下这两者的区别
JDK 动态代理:获取的是接口中的方法信息,因此如果注解是在实现类上定义的,通过代理对象获取不到这些注解。
CGLIB 动态代理:获取的是目标类中的方法信息,因此可以获取到实现类上的注解。
JDK 动态代理
适用场景:
- 目标类必须实现一个或多个接口。
- 代理类会实现这些接口并代理方法调用。
优点:
- 简单易用,直接基于 Java 反射机制。
- 性能较好,适用于代理接口的场景。
缺点:
- 只能代理接口中的方法,不能代理没有实现接口的类的方法。
示例:
java复制代码import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private final Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object proxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
CGLIB 动态代理
适用场景:
- 目标类没有实现接口,或者需要代理没有实现接口的方法。
- 代理类是目标类的子类,通过生成子类来覆盖目标类的方法。
优点:
- 可以代理没有实现接口的类。
- 能代理类中的所有方法,包括那些没有在接口中定义的方法。
缺点:
- 性能相对较差,因为需要生成子类。
- 需要额外的 CGLIB 库。
示例:
java复制代码import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private final Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object proxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
}
判断逻辑示例
你可以根据目标类的类型来选择适当的代理方式:
java复制代码public class ProxyFactory {
public static <K, V> ICache<K, V> createProxy(Object target) {
Class<?> clazz = target.getClass();
// 判断是否是接口或者 Proxy 类
if (clazz.isInterface() || Proxy.isProxyClass(clazz)) {
return (ICache<K, V>) new DynamicProxy(target).proxy();
}
// 否则使用 CGLIB 动态代理
return (ICache<K, V>) new CglibProxy(target).proxy();
}