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();
    }
posted on 2024-07-12 17:40  爱为斯坦  阅读(9)  评论(0编辑  收藏  举报