JDK动态代理和CGLIB动态代理的区别及实例

简介: JDK动态代理和CGLIB动态代理的区别及实例

JDK 动态代理和 CGLIB 动态代理是两种常用的 Java 动态代理技术,它们在实现原理和应用场景上存在一些区别。

JDK 动态代理JDK 动态代理是基于接口的代理技术。它利用 Java 的反射机制,在运行时创建代理类和代理实例。JDK 动态代理要求目标对象必须实现至少一个接口,代理类会实现与目标对象相同的接口,并且具有相同的方法签名。当代理对象的方法被调用时,实际上是通过InvocationHandler 将方法调用转发给了目标对象。JDK 动态代理只能代理接口,无法代理类。

优点:

  • 简单易用,无需额外的库或依赖。
  • 适用于代理接口的场景。

缺点:

  • 只能代理实现了接口的类。
  • 代理类的性能相对较低。

CGLIB 动态代理 CGLIBCode Generation Library)动态代理是基于类的代理技术。它通过生成目标类的子类作为代理类,并重写目标方法来实现代理功能。CGLIB 动态代理不要求目标对象实现接口,可以代理普通的类。当代理对象的方法被调用时,实际上是通过MethodInterceptor 将方法调用转发给了目标对象。

优点:

  • 可以代理普通的类,无需实现接口。
  • 生成的代理类性能比 JDK 动态代理高。

缺点:

  • 生成的代理类是目标类的子类,因此无法代理被 final 修饰的类和方法。
  • 需要依赖 CGLIB 库。

选择使用 JDK 动态代理还是 CGLIB 动态代理取决于具体的场景和需求。如果目标对象只实现了接口,并且对性能要求较低,可以选择 JDK 动态代理;如果目标对象为普通类,或者需要更高的性能,可以选择 CGLIB 动态代理。

总结起来,JDK 动态代理适用于代理接口,而 CGLIB 动态代理适用于代理类。

下面是一个使用 JDK 动态代理的示例代码:

首先,定义一个接口UserService,包含了一些方法:

publicinterfaceUserService {
voidaddUser(Stringusername);
voiddeleteUser(Stringusername);
}


接下来,创建一个实现了该接口的目标对象UserServiceImpl

publicclassUserServiceImplimplementsUserService {
@OverridepublicvoidaddUser(Stringusername) {
System.out.println("添加用户:"+username);
    }
@OverridepublicvoiddeleteUser(Stringusername) {
System.out.println("删除用户:"+username);
    }
}


然后,编写一个 InvocationHandler 实现类UserInvocationHandler,用于处理代理对象的方法调用:

importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
publicclassUserInvocationHandlerimplementsInvocationHandler {
privatefinalUserServicetarget; // 目标对象publicUserInvocationHandler(UserServicetarget) {
this.target=target;
    }
@OverridepublicObjectinvoke(Objectproxy, Methodmethod, Object[] args) throwsThrowable {
System.out.println("Before method: "+method.getName());
Objectresult=method.invoke(target, args);
System.out.println("After method: "+method.getName());
returnresult;
    }
}


最后,在测试类中使用 JDK 动态代理创建代理对象并调用方法:

importjava.lang.reflect.Proxy;
publicclassMain {
publicstaticvoidmain(String[] args) {
UserServiceuserService=newUserServiceImpl();
// 创建代理对象UserServiceproxy= (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
newUserInvocationHandler(userService)
        );
// 调用代理对象的方法proxy.addUser("Alice");
proxy.deleteUser("Bob");
    }
}

运行上述代码,输出结果如下:

Beforemethod: addUser添加用户:AliceAftermethod: addUserBeforemethod: deleteUser删除用户:BobAftermethod: deleteUser


以上示例演示了使用 JDK 动态代理,通过Proxy.newProxyInstance()创建代理对象,将需要代理的目标对象以及自定义的 InvocationHandler 传入。在 InvocationHandler 中,可以在方法调用前后执行额外的逻辑。

下面是一个使用 CGLIB 动态代理的示例代码:

首先,引入 CGLIB 的相关依赖。在 Maven 中,可以这样添加依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.4.0</version></dependency>

定义一个普通的目标类UserService,包含一些方法:

publicclassUserService {
publicvoidaddUser(Stringusername) {
System.out.println("添加用户:"+username);
    }
publicvoiddeleteUser(Stringusername) {
System.out.println("删除用户:"+username);
    }
}


接下来,编写一个 MethodInterceptor 实现类UserMethodInterceptor,用于处理代理对象的方法调用:


importnet.sf.cglib.proxy.MethodInterceptor;
importnet.sf.cglib.proxy.MethodProxy;
importjava.lang.reflect.Method;
publicclassUserMethodInterceptorimplementsMethodInterceptor {
@OverridepublicObjectintercept(Objectobj, Methodmethod, Object[] args, MethodProxyproxy) throwsThrowable {
System.out.println("Before method: "+method.getName());
Objectresult=proxy.invokeSuper(obj, args);
System.out.println("After method: "+method.getName());
returnresult;
    }
}

在测试类中使用 CGLIB 创建代理对象并调用方法:

importnet.sf.cglib.proxy.Enhancer;
publicclassMain {
publicstaticvoidmain(String[] args) {
UserServiceuserService=newUserService();
// 创建 Enhancer 对象Enhancerenhancer=newEnhancer();
// 设置目标类为父类enhancer.setSuperclass(UserService.class);
// 设置回调对象enhancer.setCallback(newUserMethodInterceptor());
// 创建代理对象UserServiceproxy= (UserService) enhancer.create();
// 调用代理对象的方法proxy.addUser("Alice");
proxy.deleteUser("Bob");
    }
}

运行上述代码,输出结果如下:

Beforemethod: addUser添加用户:AliceAftermethod: addUserBeforemethod: deleteUser删除用户:BobAftermethod: deleteUser

以上示例演示了使用 CGLIB 动态代理,通过Enhancer创建代理对象。在创建代理对象时,需要设置目标类和回调对象。回调对象即实现了MethodInterceptor接口的自定义拦截器,在拦截器中可以在方法调用前后执行额外的逻辑。

 

相关文章
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
Java API 开发者
Jdk动态代理为啥不能代理Class?
该文章主要介绍了JDK动态代理的原理以及为何JDK动态代理不能代理Class。
Jdk动态代理为啥不能代理Class?
|
2月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
|
2月前
|
存储 Java
【Java集合类面试七】、 JDK7和JDK8中的HashMap有什么区别?
JDK7中的HashMap使用数组加链表解决冲突,而JDK8增加了红黑树结构以优化链表过长时的性能,提高查找效率。
|
3月前
|
Java 编译器 程序员
JVM常见面试题(一):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别
JVM常见面试题(一):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别
JVM常见面试题(一):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别
|
2月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
82 0
|
2月前
|
Java 编译器 测试技术
Java零基础教学(03):如何正确区别JDK、JRE和JVM??
【8月更文挑战第3天】Java零基础教学篇,手把手实践教学!
46 2
|
2月前
|
人工智能 Java 编译器
Java零基础(3) - 区别JDK、JRE和JVM
【8月更文挑战第3天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
53 1
|
2月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
87 0
|
2月前
|
缓存 Java 编译器
JRE、JDK、JVM 和 JIT 之间的区别详解
【8月更文挑战第22天】
41 0