cglib动态代理,无法实现对final方法的代理采坑

有个同步实时数据的任务需求,要求先清空表再将新的同步数据入库,并保证原子性。所以一开始想到的是继承原有的定时器框架基类,并将数据层的Mapper引入,直接将业务逻辑写入到定时器中,然后在业务逻辑的方法上加上spring的Transational注解。

这个方案直接踩了两个坑:
1、定时器的入口是拿到容器的bean,然后调用一个final实现的schedule方法。因为在实现类里面搞了@Transational注解,所以schedulerTask对象实际上是spring 利用cglib生成的动态代理对象。debug到schedule方法的时候发现进来的对象是动态代理对象,由于spring对动态代理对象的master字段做注入操作,所以master字段为空,直接报了空指针异常。

在这里插入图片描述

原理:
之前正常写@Transational注解一般都没啥问题,正常调用方法后deubg时进来的都是被代理的对象。这次怎么进来的对象直接是动态代理对象呢?
为了一探究竟,查看debug调用栈,发现直接就到schedule函数了,没有经历过cglib的任何interceptor,所以难怪直接进来的就是就是动态代理对象。

在这里插入图片描述

这里又进入疑惑了,为啥这个schedule函数不经历任何的interceptor然后在调用被代理对象的schedule函数呢?我们知道,其实动态代理无非就是在运行时动态生成动态代理类,所以想办法将动态代理类下载到本地,看下生成的源码到底是咋样的。cglib下载类到本地,只需要增加代码:System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “D:\test”); 在这里顺便补充jdk动态代理的:System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “D:\test”);

在这里插入图片描述
在这里插入图片描述

将生成的class拖进idea就可以反编译了查看源码了。观察一段时间源码之后发现,源码里面没有schedule函数,所以这里也证实了为啥debug直接进入动态代理对象的schedule函数了,直接继承了基类的schedule函数,没有做任何处理。再观察源码,发现基类和实现类的其他函数都有,唯独就没有schedule,直接麻了。再对比下schedule函数和其他函数的区别,发现schedule函数有final修饰,联想到cglib动态代理是继承实现,jdk动态代理是基于接口实现,会不会是final函数不能被子类复写,所以没有在动态代理类里面生成schedule函数。然后百度一搜,果然,cglib动态代理,无法实现对final方法的代理。
2、第二个坑有时间再更新了,大概是被代理对象的A函数直接调用被代理对象的@Transational注解的函数的时候,事务是失效的。可以搜索sprig事务失效的常见场景。记住一个原理就行:要想事务有效,必须进入动态代理对象的函数,不然执行不到切面的东西。
省流:cglib动态代理,无法实现对final方法的代理

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值