通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

Java JDK 和 CGLib 动态代理怎么实现

Java JDK 和 CGLib 动态代理怎么实现

Java JDK动态代理和CGLib动态代理都可以实现在运行时动态创建代理对象,从而在不修改源码的情况下增强或控制对目标对象的访问。JDK动态代理通过反射机制实现、它要求目标对象必须实现接口、而CGLib动态代理则通过继承目标类的方式实现,通常用于无法实现接口的类。接下来,我们将详细探讨如何实现JDK和CGLib动态代理。

一、JDK动态代理的实现

JDK动态代理是基于接口实现的,它使用java.lang.reflect.Proxy类来创建代理对象,并且通过实现InvocationHandler接口自定义方法在调用处理器中处理方法调用。

创建InvocationHandler实现类

首先,定义一个InvocationHandler接口的实现类,此类会重写invoke方法,以定义在方法调用时所执行的代理逻辑。

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

// 目标对象,通过反射来调用目标方法

private Object target;

public MyInvocationHandler(Object target) {

this.target = target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 在调用具体方法前可以添加自定义操作

System.out.println("Before method call");

// 通过反射调用目标对象的方法

Object result = method.invoke(target, args);

// 在调用具体方法后可以添加自定义操作

System.out.println("After method call");

return result;

}

}

使用Proxy创建代理对象

通过Proxy.newProxyInstance方法创建一个实现了目标接口的代理对象。

import java.lang.reflect.Proxy;

public class ProxyFactory {

public static Object getProxy(Object target) {

return Proxy.newProxyInstance(

target.getClass().getClassLoader(), // 目标类的类加载器

target.getClass().getInterfaces(), // 目标类实现的接口

new MyInvocationHandler(target) // InvocationHandler实现类

);

}

}

二、CGLib动态代理的实现

CGLib通过继承目标类在运行时生成的子类来实现,它依赖于net.sf.cglib.proxy.Enhancer类和MethodInterceptor接口。

创建MethodInterceptor实现类

首先,定义一个MethodInterceptor接口的实现类,类似InvocationHandler,这个类也需要重写一个方法,不同的是这里重写的是intercept方法。

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

public class MyMethodInterceptor implements MethodInterceptor {

// 实现MethodInterceptor接口的intercept方法,定义代理逻辑

@Override

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

// 在调用方法前可以执行某些操作

System.out.println("Before method call");

// 调用代理对象父类的方法(即目标类的方法)

Object result = proxy.invokeSuper(obj, args);

// 在调用方法后可以执行某些操作

System.out.println("After method call");

return result;

}

}

使用Enhancer创建代理对象

使用Enhancer类生成代理对象,Enhancer是CGLib提供的一个类生成类。

import net.sf.cglib.proxy.Enhancer;

public class CglibProxyFactory {

public static Object getProxy(Class<?> clazz) {

// 创建Enhancer对象

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(clazz); // 设置需要代理的类

enhancer.setCallback(new MyMethodInterceptor()); // 设置MethodInterceptor实现类

return enhancer.create(); // 创建代理对象

}

}

通过上面的步骤,我们可以生成任意类的子类并在运行时通过拦截器对方法调用进行控制。这两种动态代理的底层实现机制不同,但都达到了在不修改源码的前提下增强类的行为的目的。实际应用中,这两种代理有各自的使用场景,JDK动态代理由于只能针对实现了接口的类,因此使用面相对窄;而CGLib动态代理没有这个限制,但由于使用了继承,因此不能对final类以及final方法进行代理。

相关问答FAQs:

问题1: Java的JDK动态代理和CGLib动态代理分别是如何实现的?
答:Java的JDK动态代理是通过反射机制来实现的,它要求被代理的目标类必须实现一个接口,代理类在运行时动态生成,在调用代理方法时会通过反射调用目标类的方法。而CGLib动态代理则是通过继承目标类来实现的,代理类是目标类的子类,在调用代理方法时直接调用子类的方法,因此不要求目标类实现接口。

问题2: JDK动态代理和CGLib动态代理在使用场景上有什么区别?
答:JDK动态代理适用于基于接口的代理,它要求被代理的目标类实现一个接口,在运行时生成代理对象。而CGLib动态代理适用于对类进行代理,它直接继承目标类并生成代理对象。因此,如果目标类已经实现了接口,我们可以使用JDK动态代理;如果目标类没有实现接口或者我们想要代理类的所有方法,我们可以使用CGLib动态代理。

问题3: JDK动态代理和CGLib动态代理在性能上有什么区别?
答:JDK动态代理在生成代理对象时,需要通过反射调用目标类的方法,这个过程相对较慢,适用于对性能要求不高的场景。而CGLib动态代理通过继承目标类,直接调用子类的方法,省去了反射的过程,因此性能比JDK动态代理更高。但是CGLib生成的代理类需要动态加载到JVM中,所以在启动时会稍微慢一些。因此,在性能要求较高的场景下,可以考虑使用CGLib动态代理。

相关文章