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 创建代理时的常见做法。

posted @   Eiffelzero  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示