问题:

通过debug发现result.removeAll的时候 删不了

public boolean equals(Object obj) {
return obj instanceof OspSpringBoot2Initializer.OspBean && this.bean.equals(((OspSpringBoot2Initializer.OspBean)obj).bean);
}

this.bean.equals(((OspSpringBoot2Initializer.OspBean)obj).bean 这里返回了false



明明地址一致,那为什么返回了false?

定位问题:

进一步定位。



通过debug定位到: 最终调用java.lang.Object#equals方法的时候,this和obj的引用不一致所以返回false

通过栈帧可以看到:

调用了cglib增强类的equals方法

通过arthas jad 命令反编译出cglib类的代码

public final boolean equals(Object object) {
boolean[] arrbl = SalesNormalPoolService$$EnhancerByCGLIB$$e87bde91.$jacocoInit();
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor != null) {
arrbl[3] = true;
} else {
SalesNormalPoolService$$EnhancerByCGLIB$$e87bde91.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
arrbl[4] = true;
}
if (methodInterceptor != null) {
boolean bl;
Object object2 = methodInterceptor.intercept((Object)this, CGLIB$equals$0$Method, new Object[]{object}, CGLIB$equals$0$Proxy);
if (object2 == null) {
bl = false;
arrbl[5] = true;
} else {
bl = (Boolean)object2;
arrbl[6] = true;
}
arrbl[7] = true;
return bl;
}
arrbl[8] = true;
return super.equals(object);
}

这里结果依赖于methodInterceptor.intercept((Object)this, CGLIB$equals$0$Method, new Object[]{object}, CGLIB$equals$0$Proxy);

我们继续看下intercept 这个方法

public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//.. 省略 不会走这里的
}



发现是通过反射调用java.lang.Object#equals方法,此时是this.equals(args[0]) 发现地址不一致 结果返回false。

所以bug就定位到

method.invoke(this, args);

解决:

正确写法应该是:

methodProxy.invokeSuper(o, args);

public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return methodProxy.invokeSuper(o, args);
}
//.. 省略 不会走这里的
}

修改过后



在调用java.lang.Object#equals时



传入了o 和 args[0] ,它们两个地址相同,所以返回true

我们继续看下栈帧:



现在有调用CGLIB$equals$0:-1, SalesNormalPoolService$$EnhancerByCGLIB$$e87bde91

final boolean CGLIB$equals$0(Object object) {
boolean[] arrbl = SalesNormalPoolService$$EnhancerByCGLIB$$e87bde91.$jacocoInit();
arrbl[2] = true;
return super.equals(object);
}





也就是 现在的调用是:o == args[0] → true

以前的调用是:this == args[0] → false

cglib 代理类自己equals自己 返回false问题的更多相关文章

  1. spring查看生成的cglib代理类源码详解

    1.让程序阻塞(抛出异常会导致程序结束,所以在抛出异常之前阻塞) 2. windows控制台 cd到jdk目录下的lib目录,找到sa-jdi.jar 执行: java -classpath sa-j ...

  2. 从数据库取出两个同样的字符串用equals比较返回false

    1. 从网上搜索原因,大概总结为三点 1.1 取数据的两个数据库编码不一样,需要统一编码 1.2 字符类型不一样,可能一个为nchar一个为varchar 1.3 从数据库取出的数据有空格,需要tri ...

  3. JDK动态代理和cglib代理

    写一个简单的测试用例,Pig实现了Shout接口 public class MyInvocation implements InvocationHandler { Object k; public M ...

  4. Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

    我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...

  5. 关于Object类的equals方法和hashCode方法

    关于Object类的equals的特点,对于非空引用: 1.自反性:x.equals(x) return true : 2.对称性:x.equals(y)为true,那么y.equals(x)也为tr ...

  6. 分享知识-快乐自己:三种代理(静态、JDK、CGlib 代理)

    1):代理模式(静态代理)点我下载三种模式源码 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由 业务实现类.业务代理类 两部分组成 ...

  7. Java代理模式精讲之静态代理,动态代理,CGLib代理

    代理(Proxy)是一种设计模式,通俗的讲就是通过别人达到自己不可告人的目的(玩笑). 如图: 代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象 这三个代理模式,就 ...

  8. java动态代理类

    很有意思的一个东西,在java.lang.reflect包下 示例代码 package com.guangshan.test.proxy; import java.lang.reflect.Invoc ...

  9. CGLIB 和 JDK生成动态代理类的区别(转)

    文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...

  10. JDK和CGLIB生成动态代理类的区别

     关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...

随机推荐

  1. Ceph PG状态介绍

    本文分享自天翼云开发者社区<Ceph PG状态介绍>,作者:wwwdl 一.基本概念 size:副本数(如三副本,size=3): min_size:支持可读写的最小副本数(如三副本,mi ...

  2. linux ubuntu更改软件源

    更换步骤 sudo cp /etc/apt/sources.list /etc/apt/sources.list.back sudo vim /etc/apt/sources.list 替换为下面内容 ...

  3. .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案

    前言 随着物联网(IoT)技术的迅猛发展,智能设备之间的互联互通变得越来越重要. 推荐一套基于 C# 的高效 IoT 系统,该系统运行在 Linux 开发板上,并支持 Modbus RS485 传感器 ...

  4. C# 全角字符和半角字符相互转换

    参考链接:https://blog.csdn.net/willingtolove/article/details/106923879 1. 全角转半角 /// <summary> /// ...

  5. C# USB 摄像头 OpenCV 视频picBox呈现,抓拍图像保存呈现。没有注释版本。

    1.winform 应用程序,两个picturebox空间,一个用于视频呈现,一个用于抓拍呈现. 2.引用包OpenCvSharp4.OpenCvSharp4.Extensions.OpenCvSha ...

  6. 【ABAQUS 二次开发笔记】读入TXT分析结果&输出csv文件

    abaqus分析之后,很多结果可以输出dat,msg,sta等文件中.可以用记事本.notpad++.editplus等软件打开编辑. 但是往往无法直接用excel.origin等软件打开,比如对结构 ...

  7. https证书中的subject alternative name字段作用及如何生成含该字段的证书

    背景 最近,某个运维同事找到我,说测试环境的某个域名(他也在负责维护),假设域名为test.baidu.com,以前呢,证书都是用的生产的证书,最近不让用了.问为啥呢,说不安全,现在在整改了,因为证书 ...

  8. ffmpeg合并时音画不同步问题及音频软编码实现记录

    最近因为耳机3.5mm接口的一些干扰问题,舍弃了之前的接入方式,需要重新实现网络音频流的接入,在这个过程中遇到了一些问题,特来记录一下~ 一.网络音频流的接入 这个音频流来源各不相同,我这里是udp广 ...

  9. C# 中比较实用的关键字,基础高频面试题!

    前言 在C#编程中关键字是构建逻辑和实现功能的基石,它承载着编程语言的语法规则和编程智慧.熟练掌握这些基础高频关键字对提升编程能力和面试表现至关重要,它们是日常开发和解决复杂问题的关键. DotNet ...

  10. Anaconda指定目录安装终极指南+避坑大全

    最近被Python环境搞疯了吧?一个项目跑起来另一个就报错?用Conda环境隔离大法就对了!但默认安装竟吃掉根分区8G的硬盘?今天手把手教你迁移安装目录+实战部署AI项目. 今天测试AIREPORT, ...