当前位置: 首页 > news >正文

jdk动态代理和cglib动态代理对比

jdk动态代理和cglib动态代理对比:

CGLIB 和 JDK 动态代理都可以用来在运行时生成代理对象

1. 基本概念

  • JDK 动态代理:只代理接口(interface),无法代理类。它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现动态代理。
  • CGLIB 动态代理:可以代理类和接口。它通过生成目标类的子类来创建代理对象,因此可以代理没有实现接口的类。

2. 使用场景

  • JDK 动态代理:适用于目标对象实现了一个或多个接口的情况。Spring AOP 默认使用 JDK 动态代理,如果目标对象没有实现接口,则使用 CGLIB。
  • CGLIB 动态代理:适用于目标对象没有实现接口或者需要代理类而不是接口的情况。

3. 性能

  • JDK 动态代理:由于使用了反射机制,性能相对较低,但对于简单接口的代理,性能差异不明显。
  • CGLIB 动态代理:通过生成字节码来创建代理对象,性能比 JDK 动态代理更高,但是生成字节码的开销较大。

 4. 优缺点总结

  • JDK 动态代理

    • 优点:简单,直接使用 JDK 提供的 API,无需额外依赖。
    • 缺点:只能代理接口,性能较低。
  • CGLIB 动态代理

    • 优点:可以代理类和接口,性能较高。
    • 缺点:需要额外的 CGLIB 库,生成字节码的开销较大,无法代理 final 类和方法。

jdk动态代理:

1. 被代理的接口和实现类:

public interface Subject {void doSomething();
}public class RealSubject implements Subject {@Overridepublic void doSomething() {System.out.println("Doing something in RealSubject");}
}

2. 创建 InvocationHandler 实现类: 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {private final Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method execution");Object result = method.invoke(target, args);System.out.println("After method execution");return result;}
}

3. 使用 Proxy 创建代理对象: 

import java.lang.reflect.Proxy;public class JdkProxyDemo {public static void main(String[] args) {Subject realSubject = new RealSubject();Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),new MyInvocationHandler(realSubject));proxy.doSomething();}
}

cglib动态代理使用步骤

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它可以在运行时动态生成字节码。CGLIB 常用于创建代理对象,特别是在 Spring 框架中,用于 AOP(面向切面编程)

1. 添加 CGLIB 依赖项:
如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖项:

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

2. 被代理的类

public class RealSubject {private String field;public String getField() {return field;}public void setField(String field) {this.field = field;}public void doSomething() {System.out.println("Doing something in RealSubject");}
}

3. 创建 MethodInterceptor:

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method execution");Object result = proxy.invokeSuper(obj, args);System.out.println("After method execution");return result;}
}

4.创建代理对象:

import net.sf.cglib.proxy.Enhancer;public class CglibProxyDemo {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(RealSubject.class);enhancer.setCallback(new MyMethodInterceptor());RealSubject proxy = (RealSubject) enhancer.create();proxy.doSomething();}
}

RealSubject 是被代理的类,MyMethodInterceptor 实现了 MethodInterceptor 接口,用于在方法执行前后添加额外的逻辑。Enhancer 类用于创建代理对象。

运行 CglibProxyDemo 类时,你会看到如下输出:

cglib jdk17 的问题:

jdk17 需要增加如下配置,否则会 报错:

--add-opens=java.base/java.lang=ALL-UNNAMED

在 JDK 9 及其之后的版本(包括 JDK 17)中,Java 引入了模块系统(Project Jigsaw),这使得访问某些内部 API 和模块变得更加严格。--add-opens 参数允许你在运行 Java 应用时开放特定的模块和包给未命名模块(通常是类路径上的代码),以便它们可以进行深层次的反射操作。

报错信息:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @4cdf35a9at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)at net.sf.cglib.core.ReflectUtils$1.run(ReflectUtils.java:61)at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52)at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:243)at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)... 13 more


http://www.mrgr.cn/news/81802.html

相关文章:

  • 《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(31):HTTPS和TLS/SSL
  • 【ollama通过命令行启动后如何在网页端查看运行】
  • 力扣206题——反转链表
  • Elasticsearch容器启动报错:AccessDeniedException[/usr/share/elasticsearch/data/nodes];
  • excel仅复制可见单元格,仅复制筛选后内容
  • 系统看门狗配置--以ubuntu为例
  • Linux Debian安装ClamAV和命令行扫描病毒方法,以及用Linux Shell编写了一个批量扫描病毒的脚本
  • QTday3
  • 2024第一届Solar杯应急响应挑战赛
  • iDP3复现代码数据预处理全流程(二)——vis_dataset.py
  • 使用Xilinx PCIE XDMA框架读写访问DDR3内容
  • 远方的灯塔(自创诗歌浅析)
  • Atcoder Beginner Contest 385
  • HTML4笔记
  • 【MATLAB】对连续信号采样的研究
  • 我们来学activiti -- bpmn
  • Jupyter在运行上出现错误:ModuleNotFoundError: No module named ‘wordcloud‘
  • 计算机的错误计算(一百九十四)
  • Day1 微服务 单体架构、微服务架构、微服务拆分、服务远程调用、服务注册和发现Nacos、OpenFeign
  • 【C++】球弹跳高度的计算:思路分析与优化
  • 【C++】统计正整数的位数:题目解析与代码优化
  • Python入门:7.Pythond的内置容器
  • 2-198基于Matlab-GUI的运动物体追击问题
  • 前端
  • Stable Diffusion绘画 | 电商设计海报
  • 【CSS in Depth 2 精译_096】16.4:CSS 中的三维变换 + 16.5:本章小结