User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Java   ›   正文
Java

Java—Cglib的invoke和invokeSuper区别

2021-07-05 11:23:14
838  0 0

阅读完需:约 4 分钟

简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;

依赖:

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.12</version>
        </dependency>
public class Target {
    
    public void a() {
        System.out.println("a 方法");
    }
    
    public void b() {
        System.out.println("b 方法");
    }
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyMethodInterceptor implements MethodInterceptor{

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    //obj是代理后的子类  ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象
        System.out.println("myMethodInterceptor go ");
        Object res = proxy.invokeSuper(obj, args);
        return res;
    }
}

测试

public class TestApp {

    public static void main(String[] args) {
        Enhancer e = new Enhancer();
        e.setSuperclass(Target.class);     
        e.setCallback(new MyMethodInterceptor());
        Target t=(Target) e.create();
        t.a();
    }
}
myMethodInterceptor go 
a 方法

探讨一个问题:

Target这个类里面方法写 this 就是 指的生成的Cglib子类?

在a方法中添加一句输出this

结论:Cglib代理的时候target对象中的this就是Cglib子类  (你可能觉得我说的是废话,子类对象在父类的this指的不是自身吗? 但是Spring Aop里this方法无法增强自身调用)

既然知道了this对象就是指代的自身,那我比如 this.b() 或者 b() 应该也被回调一次了 。

public class Target {
    
    public void a() {
        System.out.println(" a 方法");
        b();
    }
    
    public void b() {
        System.out.println(" b 方法");
    }
}

其他类不改动代码,测试结果如下:  果然 this.b()方法也被增强了;

myMethodInterceptor go 
a 方法
myMethodInterceptor go 
b 方法

在 b()  打个断点,下一步就跳进入 MyMethodInterceptor 的 intercept 方法里了 ;这个似乎也没有毛病,其实原因就是 invokeSuper;invokeSuper传入的参数是Cglib代理的子类 ,就相当于 调用 Target$$EnhanceredByCGLIB这个子类的b()方法,肯定会再次进入回调;

如何实现像AOP一样 调用自身无法增强呢?

public class Target {
    
    public void a() {
        System.out.println(" a 方法");
        b();
    }
    
    public void b() {
        System.out.println(" b 方法");
    }
}


public class MyMethodInterceptor implements MethodInterceptor{
// 关键点 start
    private Object target;
    
    public MyMethodInterceptor(Object target) {
        super();
        this.target = target;
    }
// 关键点 end

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("myMethodInterceptor go ");
//      Object res = proxy.invokeSuper(obj, args);
        // 关键点
        Object res = proxy.invoke(target, args);
        return res;
    }

}

public class TestApp {

    public static void main(String[] args) {
//        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\api");
        // 关键点
        Target target = new Target();
        Enhancer e = new Enhancer();
        e.setSuperclass(Target.class);
        // 关键点
        e.setCallback(new MyMethodInterceptor(target));
        Target t=(Target) e.create();
        t.a();
    }
}

测试结果如下:

myMethodInterceptor go 
 a 方法
 b 方法

这就和AOP的功能一毛一样了吧 ;  区别就在于 invoke 和 invokeSuper : 在我理解看来,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;


查看下Spring CGLIB的Aop  ,  这个就是执行完 环绕通知 、 前置通知 之后执行业务方法的地方 ,target对象存的是原生的bean,没有被CGLIB代理的对象,所以就无法实现自身调用增强;

该方法是 AopUtils的invokeJoinpointUsingReflection 

而与之相反的则是,@Configuration注解下类中 @Bean注解标注方法里的 方法调用,得到的是同一个@Bean对象;

因为 BeanMethodInterceptor 的 interceptor方法  调用的invokeSuper方法 ,比如 getMan2方法调用getMan方法,那个getMan方法调用的是 CGLIB子类的getMan方法 ,此时getMan是增强后的getMan方法,这时候就会检测ThreadLocal当前线程和当前方法是否一致了,不一致尝试从容器中获取该bean对象

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593966浏览

随机文章
Maven—pom文件详细解析
5年前
RBAC用户角色权限设计方案
5年前
Spring笔记10—动态代理
5年前
SpringCloud—的负载均衡策略
5年前
HttpServletRequest常用的方法
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593966 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付