简单的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的更多相关文章

  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. 让你看懂dart中静态成员和继承

    静态属性和静态方法 在dart中,我们可以通过关键字 static来定义静态属性和静态方法. 需要注意的是: 静态方法不能访问非静态属性[结论1] 非静态方法可以访问静态成员[结论2] 我们通过下面的 ...

  2. 小程序和h5垂直时间轴

    <template> <view class="steps"> <view class="list" v-for="(i ...

  3. uni-app之条件编译

    ifdef 仅出现在XXx平台上 仅出现在 App 平台下的代码 #ifdef APP-PLUS 需条件编译的代码 #endif <!-- 只在H5上有哈 --> <!-- #ifd ...

  4. WAIC 2024盛大召开,天翼云以全栈智算能力赋能AI时代!

    7月5日,2024世界人工智能大会期间,中国电信星辰人工智能生态论坛在上海世博中心启幕.论坛以"星辰注智,焕新领航"为主题,围绕人工智能技术发展趋势,分享中国电信与产业各界在人工智 ...

  5. Jenkins+Ant+JaCoCo的代码覆盖率集成实践

    Jenkins+Ant+JaCoCo的代码覆盖率集成实践 一.工具介绍 Jenkins: Jenkins是一个开源的.基于Java开发的持续集成工具,它可以帮助开发人员自动化构建.测试和部署软件项目. ...

  6. Q:oracle备份表语句

    oracle备份还原表语句 方法1.sql语句(同一数据库服务器) 备份 create table xxx_temp as select * from xxx; 还原 truncate table x ...

  7. ORACLE11g数据中创建DB Link方法,用于跨oracle数据库查询数据

    ---查看该用户下已建立的DB link链接 SELECT * FROM DBA_DB_LINKS --创建语句 CREATE DATABASE LINK  连接名CONNECT TO 登录名  ID ...

  8. DM SQL关联列 like 优化案例

    1.1.sql优化背景 达梦一哥们找我优化条SQL,反馈在DM8数据库执行时间很慢出不来结果, 监控工具显示这条SQL的执行时间需要20多万毫秒,安排. 1.2.慢sql和执行时间 select a. ...

  9. 理解ID3决策树

    决策树是一个树形结构,类似下面这样: 上图除了根节点外,有三个叶子节点和一个非叶子节点. 在解决分类问题的决策树中,叶子节点就表示所有的分类,比如这里的分类就有3种:无聊时阅读的邮件.需及时处理的邮件 ...

  10. WPF DockLayoutManager布局后的布局重置

    初始化布局 Logging.InfoBiz("初始化布局信息"); dockLayoutManager = new DockLayoutManager(); RestoreLayo ...