cglib 代理类 自己equals自己 返回false
简单的cglib代理示例
普通的 Java 类
package cglib;
public class UserService {
public void saveUser(String username) {
System.out.println("Saving user: " + username);
}
}
使用代理类来增强 UserService
package cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserServiceProxy implements MethodInterceptor {
private Object target;
public UserServiceProxy(Object target) {
this.target = target;
}
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 在方法执行前可以添加额外的逻辑
System.out.println("Before method: " + method.getName());
// 调用原始方法
Object result = method.invoke(target, args);
// 在方法执行后可以添加额外的逻辑
System.out.println("After method: " + method.getName());
return result;
}
}
调用
package cglib;
public class CglibMain {
public static void main(String[] args) {
UserService userService = new UserService();
// 创建代理类
UserService proxy = (UserService) new UserServiceProxy(userService).createProxy();
System.out.println(proxy.equals(proxy));
// 调用代理对象的方法
proxy.saveUser("John");
}
}
Before method: equals
After method: equals
false // 这里明显不符合我们的预期,自己equals自己 应该是为true才对
Before method: saveUser
Saving user: John
After method: saveUser

debug 发现:

来到equals方法的时候,this 是 UserService 类,obj 是cglib的代理类,所以为false
正确写法:
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 在方法执行前可以添加额外的逻辑
System.out.println("Before method: " + method.getName());
// 调用原始方法
Object result = methodProxy.invokeSuper(o, args);
// 在方法执行后可以添加额外的逻辑
System.out.println("After method: " + method.getName());
return result;
}
Before method: equals
After method: equals
true // 这里符合预期
Before method: saveUser
Saving user: John
After method: saveUser

修改代码过后:


通过栈帧可以看到,此时多了CGLIB$equals$1:-1, UserService$$EnhancerByCGLIB$$41629a0a
然后到java.lang.Object#equals方法时 this 和 obj 都是cglib 代理类,所以为true
然后我们来看下cglib代理类的equals方法和CGLIB$equals$1方法
通过arthas jad 命令反编译出cglib类的代码
public final boolean equals(Object object) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
UserService$$EnhancerByCGLIB$$41629a0a.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object2 = methodInterceptor.intercept(this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
return object2 == null ? false : (Boolean) object2;
}
return super.equals(object);
}
final boolean CGLIB$equals$1(Object object) {
return super.equals(object);
}
总结
method.invoke(target, args): 这种方式使用 Java 反射机制直接调用目标对象的方法。这对于普通的 Java 类是完全适用的,但是它会绕过 CGLIB 的代理逻辑。如果您使用这种方式,代理类中的任何增强逻辑都将被忽略。
methodProxy.invokeSuper(proxy, args): 这种方式使用 CGLIB 提供的 MethodProxy 来调用目标对象的方法。这样做会触发代理类中的增强逻辑,允许您在方法执行前后添加额外的操作。这是使用 CGLIB 创建代理时的常见做法。
cglib 代理类 自己equals自己 返回false的更多相关文章
- spring查看生成的cglib代理类源码详解
1.让程序阻塞(抛出异常会导致程序结束,所以在抛出异常之前阻塞) 2. windows控制台 cd到jdk目录下的lib目录,找到sa-jdi.jar 执行: java -classpath sa-j ...
- 从数据库取出两个同样的字符串用equals比较返回false
1. 从网上搜索原因,大概总结为三点 1.1 取数据的两个数据库编码不一样,需要统一编码 1.2 字符类型不一样,可能一个为nchar一个为varchar 1.3 从数据库取出的数据有空格,需要tri ...
- JDK动态代理和cglib代理
写一个简单的测试用例,Pig实现了Shout接口 public class MyInvocation implements InvocationHandler { Object k; public M ...
- Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现
我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...
- 关于Object类的equals方法和hashCode方法
关于Object类的equals的特点,对于非空引用: 1.自反性:x.equals(x) return true : 2.对称性:x.equals(y)为true,那么y.equals(x)也为tr ...
- 分享知识-快乐自己:三种代理(静态、JDK、CGlib 代理)
1):代理模式(静态代理)点我下载三种模式源码 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由 业务实现类.业务代理类 两部分组成 ...
- Java代理模式精讲之静态代理,动态代理,CGLib代理
代理(Proxy)是一种设计模式,通俗的讲就是通过别人达到自己不可告人的目的(玩笑). 如图: 代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象 这三个代理模式,就 ...
- java动态代理类
很有意思的一个东西,在java.lang.reflect包下 示例代码 package com.guangshan.test.proxy; import java.lang.reflect.Invoc ...
- CGLIB 和 JDK生成动态代理类的区别(转)
文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...
- JDK和CGLIB生成动态代理类的区别
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...
随机推荐
- Codeforces Round 957 (Div. 3)
题目链接:Codeforces Round 957 (Div. 3) 总结:E不懂,F差一个set去重 A. Only Pluses fag:枚举 B. Angry Monk fag:模拟 Solut ...
- .Net类型 值类型
预定义类型值类型 数据类型C#关键字(如 int.short 和 string) 从编译器映射到.NET数据类型.例如,在C#中声明一个int类型的数据时声明的实际是.Net System.Int32 ...
- NAT原理:概念、使用场景、转发流程及规则
本文分享自天翼云开发者社区<NAT原理:概念.使用场景.转发流程及规则>,作者:x****n 网络地址转换(NAT)是一种在计算机网络中将一个网络的IP地址转换为另一个网络的IP地址的技术 ...
- CRISP-DM的应用与理解
本文分享自天翼云开发者社区<CRISP-DM的应用与理解>,作者:吴****嫄 CRISP-DM是一个数据挖掘项目规划的开放标准流程框架模型,主要分为业务理解.数据理解.数据准备.建模.评 ...
- Atcoder [AGC006D] Median Pyramid Hard 题解 [ 紫 ] [ 二分 ] [ adhoc ]
Median Pyramid Hard:二分 trick 加上性质观察题. trick 我们可以二分值域,然后把大于等于它的数标记成 \(1\),其他标记为 \(0\)(有些题需要标记成 \(-1\) ...
- P5384 [Cnoi2019] 雪松果树 题解
传送门 前言 一年一度,生长在高山上的雪松果树又结果了. 第二天,雪松果树长成了一颗参天大树, 上面长满了雪松果. 求雪松果树生长周期 整活向题解. 奋力卡常 3h,纪念一下. 是的,我一个人的提交占 ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Live View Kit (1)
1.问题描述: 客户端创建实况窗后,通过Push kit更新实况窗内容,这个过程是自动更新的还是客户端解析push消息数据后填充数据更新?客户端除了接入Push kit和创建实况窗还需要做什么工作? ...
- Python异步编程进阶指南:破解高并发系统的七重封印
title: Python异步编程进阶指南:破解高并发系统的七重封印 date: 2025/2/25 updated: 2025/2/25 author: cmdragon excerpt: 本文是异 ...
- DataX - [01] 概述
DataX是阿里巴巴集团内被广泛使用的离线数据同步工具/平台.实现包括MySQL.Oracle.SQLServer.PostgreSQL.HDFS.Hive.ADS.HBase.TableStor ...
- C#语法糖foreach语句和using语句联合使用
foreach语句可以和using语句联合使用,比如你需要对多个相机设备进行一些设置,设置完就调用 Dispose() 释放相机资源, 这时可以这样写: 模拟的设备类: class Device : ...