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生成动态代理类的区别
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...
随机推荐
- 让你看懂dart中静态成员和继承
静态属性和静态方法 在dart中,我们可以通过关键字 static来定义静态属性和静态方法. 需要注意的是: 静态方法不能访问非静态属性[结论1] 非静态方法可以访问静态成员[结论2] 我们通过下面的 ...
- 小程序和h5垂直时间轴
<template> <view class="steps"> <view class="list" v-for="(i ...
- uni-app之条件编译
ifdef 仅出现在XXx平台上 仅出现在 App 平台下的代码 #ifdef APP-PLUS 需条件编译的代码 #endif <!-- 只在H5上有哈 --> <!-- #ifd ...
- WAIC 2024盛大召开,天翼云以全栈智算能力赋能AI时代!
7月5日,2024世界人工智能大会期间,中国电信星辰人工智能生态论坛在上海世博中心启幕.论坛以"星辰注智,焕新领航"为主题,围绕人工智能技术发展趋势,分享中国电信与产业各界在人工智 ...
- Jenkins+Ant+JaCoCo的代码覆盖率集成实践
Jenkins+Ant+JaCoCo的代码覆盖率集成实践 一.工具介绍 Jenkins: Jenkins是一个开源的.基于Java开发的持续集成工具,它可以帮助开发人员自动化构建.测试和部署软件项目. ...
- Q:oracle备份表语句
oracle备份还原表语句 方法1.sql语句(同一数据库服务器) 备份 create table xxx_temp as select * from xxx; 还原 truncate table x ...
- ORACLE11g数据中创建DB Link方法,用于跨oracle数据库查询数据
---查看该用户下已建立的DB link链接 SELECT * FROM DBA_DB_LINKS --创建语句 CREATE DATABASE LINK 连接名CONNECT TO 登录名 ID ...
- DM SQL关联列 like 优化案例
1.1.sql优化背景 达梦一哥们找我优化条SQL,反馈在DM8数据库执行时间很慢出不来结果, 监控工具显示这条SQL的执行时间需要20多万毫秒,安排. 1.2.慢sql和执行时间 select a. ...
- 理解ID3决策树
决策树是一个树形结构,类似下面这样: 上图除了根节点外,有三个叶子节点和一个非叶子节点. 在解决分类问题的决策树中,叶子节点就表示所有的分类,比如这里的分类就有3种:无聊时阅读的邮件.需及时处理的邮件 ...
- WPF DockLayoutManager布局后的布局重置
初始化布局 Logging.InfoBiz("初始化布局信息"); dockLayoutManager = new DockLayoutManager(); RestoreLayo ...