番禺网站建设技术,佛山微信网站开发,汕头建设,做历史课件用哪个网站比较好jdk动态代理和cglib动态代理对比#xff1a;
CGLIB 和 JDK 动态代理都可以用来在运行时生成代理对象
1. 基本概念
JDK 动态代理#xff1a;只代理接口#xff08;interface#xff09;#xff0c;无法代理类。它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.I…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动态代理使用步骤
CGLIBCode Generation Library是一个强大的高性能代码生成库它可以在运行时动态生成字节码。CGLIB 常用于创建代理对象特别是在 Spring 框架中用于 AOP面向切面编程
1. 添加 CGLIB 依赖项 如果你使用的是 Maven可以在 pom.xml 中添加以下依赖项
dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.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-opensjava.base/java.langALL-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