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

哈尔滨住房建设发展集团网站百度怎么发免费广告

哈尔滨住房建设发展集团网站,百度怎么发免费广告,装配式建筑信息平台,企业网站怎做1 已有JDK Dynamic Proxy,为什么还要CGLIB? JDK Dynamic Proxy 和 CGLib 是两种常用的代理技术,它们各自有不同的适用场景和局限性。在已经有了 JDK Dynamic Proxy 的情况下,还需要 CGLib 的原因: 1.1. 类 vs 接口 J…

1 已有JDK Dynamic Proxy,为什么还要CGLIB?

JDK Dynamic Proxy 和 CGLib 是两种常用的代理技术,它们各自有不同的适用场景和局限性。在已经有了 JDK Dynamic Proxy 的情况下,还需要 CGLib 的原因:


1.1. 类 vs 接口

JDK Dynamic Proxy 只能代理实现了接口的类。
它通过 java.lang.reflect.Proxy 类生成代理对象,要求目标类必须实现一个或多个接口。

CGLib 可以代理没有实现接口的类。
它通过字节码操作(使用 ASM 库)动态生成目标类的子类来实现代理。


1.2. 功能限制

JDK Dynamic Proxy 无法代理类中的私有方法、静态方法或 final 方法。
它只能代理接口中声明的方法。

CGLib 可以代理类中的非私有方法(包括 protected 和 public 方法),并且支持对类本身进行增强。


1.3. 字节码增强需求

CGLib 提供了更强大的字节码操作能力,适用于需要深度修改类行为的场景。
例如,AOP 框架中可能需要拦截构造函数调用或修改类的内部逻辑,这在 JDK Dynamic Proxy 中是无法实现的。

2 怎样使用CGLIB实现动态代理?

CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它广泛应用于AOP框架中,如Spring AOP。CGLIB通过生成一个被代理类的子类来实现代理,从而避免了Java代理的接口限制。以下是使用CGLIB实现动态代理的基本步骤:


2.1添加依赖

如果你使用的是Maven项目,需要在pom.xml中添加CGLIB的依赖:

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

2.2创建被代理类

创建一个普通的Java类,这个类的方法将被代理。这里使用前面讲过的示例代码: BusinessCalculator.

public class BusinessCalculator implements Calculator {@Overridepublic Long add(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a + b;}return result;}@Overridepublic Long subtract(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a - b;}return result;}@Overridepublic Long multiply(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a * b;}return result;}@Overridepublic Long divide(Integer a, Integer b) {long result = 0;for(int i=0; i<100000000; i++) {result += i + a / b;}return result;}
}

2.3实现MethodInterceptor接口

创建一个拦截器类,实现net.sf.cglib.proxy.MethodInterceptor接口,并重写intercept方法

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;public class BusinessCalculatorInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());// 调用原始方法Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}
}

2.4. 创建代理对象

使用CGLIB的Enhancer类创建目标类的代理对象。
示例代码如下:

import net.sf.cglib.proxy.Enhancer;public class CglibProxyDemo {public static void main(String[] args) {// 创建Enhancer对象Enhancer enhancer = new Enhancer();// 设置目标类enhancer.setSuperclass(BusinessCalculator.class);// 设置回调函数enhancer.setCallback(new BusinessCalculatorInterceptor());// 创建代理对象BusinessCalculator proxyInstance = (BusinessCalculator) enhancer.create();// 调用代理对象的方法System.out.println("Result of add: " + proxyInstance.add(1, 2));System.out.println("Result of subtract: " + proxyInstance.subtract(5, 3));System.out.println("Result of multiply: " + proxyInstance.multiply(6, 7));System.out.println("Result of divide: " + proxyInstance.divide(8, 9));}}

注意事项
目标类不能为final:CGLIB通过生成目标类的子类来实现动态代理,因此目标类不能声明为final。
性能开销:CGLIB在运行时生成字节码,可能会带来一定的性能开销。


通过以上步骤,您可以成功使用CGLIB实现动态代理。

2.5 运行效果

我的运行环境是JDK17, 运行上面代码时抛出异常:

Exception in thread "main" java.lang.ExceptionInInitializerErrorat org.derek.CglibProxyDemo.main(CglibProxyDemo.java:9)
Caused by: net.sf.cglib.core.CodeGenerationException: 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 @4f2410acat net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:464)at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339)at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174)at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153)at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)... 1 more

这个错误是由于 Java 9 及以上版本引入的模块化系统(Java Platform Module System, JPMS)导致的。模块化系统对类的访问进行了严格的限制,而CGLIB尝试通过反射访问 java.lang 包中的类或方法,从而导致 java.lang.ClassFormatError。

解决方案:

  • IntelliJ IDEA

    1. 打开运行配置(Run Configurations)。

    2. 在 VM options 中添加 --add-opens java.base/java.lang=ALL-UNNAMED

添加上面的VM 参数后,运行效果如下:
 

"C:\Program Files\Java\jdk-17\bin\java.exe" --add-opens java.base/java.lang=ALL-UNNAMED " org.derek.CglibProxyDemo


Before method: add
After method: add
Result of add: 5000000250000000
Before method: subtract
After method: subtract
Result of subtract: 5000000150000000
Before method: multiply
After method: multiply
Result of multiply: 5000004150000000
Before method: divide
After method: divide
Result of divide: 4999999950000000

3 CGLIB 实现动态代理的原理?

CGLIB 实现动态代理的原理主要基于字节码生成技术。以下是其核心原理:

3.1. 子类生成

CGLIB 通过在运行时动态生成目标类的子类来实现代理。它会继承目标类,并重写其中的所有非 final 方法。
继承机制:CGLIB 创建的目标类的子类会覆盖父类的方法,从而可以在方法调用前后插入自定义逻辑。
限制条件:目标类不能是 final 类型,且方法不能是 final 或 static,因为这些方法无法被子类覆盖。

3.2. 拦截器回调

CGLIB 使用回调机制(如 MethodInterceptor)来拦截目标方法的调用。当代理对象的方法被调用时,实际执行的是子类中重写的方法,而该方法会通过回调机制将控制权交给拦截器。
核心接口:MethodInterceptor 是 CGLIB 提供的核心接口,开发者需要实现该接口的 intercept 方法。
拦截逻辑:在 intercept 方法中,可以添加方法调用前后的逻辑,并通过MethodProxy.invokeSuper 调用原始方法。

3.3. 字节码生成

CGLIB 基于 ASM(一个 Java 字节码操作框架)生成字节码。它会在运行时动态创建一个新的类,该类继承了目标类并实现了所需的代理逻辑。
字节码操作:CGLIB 会解析目标类的字节码结构,生成一个新的子类字节码,并加载到 JVM 中。
性能优化:由于字节码生成和加载的过程较为复杂,CGLIB 的初始化开销较大,但一旦生成完成,运行时性能较高。

3.4. Enhancer 工具类

CGLIB 提供了 Enhancer 类作为核心工具,用于创建代理对象。
设置父类:通过 enhancer.setSuperclass(Class) 指定目标类。
设置回调:通过 enhancer.setCallback(Callback) 设置拦截器。
创建代理:调用 enhancer.create() 方法生成代理对象

3.5. 方法调用流程

以下是 CGLIB 动态代理的方法调用流程:
用户调用代理对象的方法。
代理对象(实际上是目标类的子类)拦截该方法调用。
调用 MethodInterceptor.intercept 方法,执行拦截逻辑。
在拦截器中通过 MethodProxy.invokeSuper 调用目标类的原始方法。
返回结果给用户。

3.6 示例代码说明

结合上下文中的 BusinessCalculator 类的add方法:

public class BusinessCalculator {public Long add(Integer a, Integer b) {long result = 0;for (int i = 0; i < 100000000; i++) {result += i + a + b;}return result;}
}

GLIB 会生成一个 BusinessCalculator 的子类,

BusinessCalculator$$EnhancerByCGLIB$$9b8a9c45

子类中包含下面的代码:

public final Long add(Integer var1, Integer var2) {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000 != null ? (Long)var10000.intercept(this, CGLIB$add$0$Method, new Object[]{var1, var2}, CGLIB$add$0$Proxy) : super.add(var1, var2);}

子类会覆盖 add 方法,并在方法内部调用拦截器的 intercept 方法。
拦截器中可以通过 MethodProxy.invokeSuper 调用原始的 add 方法。

怎样查看所有生成的源文件?

// 启用CGLIB调试模式,将生成的字节码文件保存到指定目录
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "net\\cglib");

感兴趣的童鞋,可以添加上面的代码,查看生成的类的源文件。结构如下:

总结
CGLIB 的核心原理是通过字节码生成技术动态创建目标类的子类,并利用回调机制拦截方法调用。相比 JDK 动态代理(基于接口),CGLIB 更适合对没有实现接口的类进行代理,但在性能和灵活性上各有优劣。

http://www.cadmedia.cn/news/12121.html

相关文章:

  • 网站保姆-源码下载搜索引擎营销怎么做
  • 移动互联网开发天气预报实现效果报告杭州seo搜索引擎优化
  • 商城型网站建设核心关键词和长尾关键词举例
  • 石家庄大型网站建站关键词seo服务
  • wordpress中文页面唐山seo排名优化
  • 网站建设推进会讲话稿网店网络营销与推广策划书
  • 免备案的网站建设360搜索推广官网
  • 开发软件下载网站搜一搜
  • 江都建设总部网站福州seo网址优化公司
  • 营销型网站建设的特色百度人工客服电话24小时
  • 白云建设网站seo排名工具有哪些
  • 无锡门户网站制作服务陕西疫情最新消息
  • 福田网站建设龙岗网站建设东莞网站制作模板
  • 个人简历ppt苏州网站优化公司
  • 四川省城乡住房建设部网站网络营销就是
  • 免费企业网站如何建设打开百度一下
  • 注册网站不用手机短信验证的网页制作软件
  • 常州新北建设局网站网站推广及seo方案
  • 外部链接链轮的建设对于网站提google seo 优化招聘
  • 邯郸网站建设信息搜索引擎营销
  • 贵阳网站建设培训学校百度下载应用
  • 如何在网上建立自己的网站私人做网站建设
  • 黄金网站下载免费营销网站模板
  • 成都装修公司一览表seo百度关键字优化
  • 天津关键词优化效果百度seo优化软件
  • 什么是网站后台seo哪家公司好
  • 上海网站建设找缘魁企业网站源码
  • 网站建设文化流程新闻今天
  • 上海网站推广提供商企业邮箱如何申请注册
  • 网站收录查询代码自动点击器怎么用