Spring事务注解失效,显式使用代理对象后报空指针异常

最近有同事在开发Spring Boot的时候遇到了注解失效问题,和解决失效问题后出现空指针的问题。

首先介绍下问题场景,在业务层类A中对a方法进行拆分,把数据库操作拆到了b方法中,并加上了@Transactional注解,但是实际使用中

并没有实现事务,异常不会回滚,也就是说注解失效了。随后在网上查阅了部分资料,他打算显示的获取代理,然后再执行,这时却抛出

了空指针异常,这让他相当的困惑。

@Service
@Slf4j
public class A {

    @Autowired
    private Service1 service1;
    
    public void a() {
        //业务逻辑处理
        b();
    }

    @Transactional
    private void b() {
        //数据库dao层的操作集合
    }
}

开始分析问题

我们都知道Spring的注解实际上是用的Aop编程,动态代理的形式加入的。注解失效的问题,大概率就是在代理的过程中出了问题,

这里先简单介绍下关于Spring的动态代理的流程

Spring会针对类A产生一个代理类A',A'是继承自类A,同时代理A'中有一个拦截器的实例,它会将所有对自己方法的调用都转为调用到拦截器中

而拦截器Handler里存在着类A的一个实例,这个实例已经被Spring的容器注入了@Autowired申明的对象(后面有用),当外部调用到A'时,实际上是由

拦截器调用了自己维护的实例执行的。

在以上的流程里,一般动态代理生成的注解实际上都是把逻辑加到了拦截器中,在执行实例前后加入要织入的逻辑。

但是在问题代码里,a方法调用b方法实际上,是用了this.b(),那获取的是当前对象实例(拦截器中维护的实例),这根本没走到代理,也就是说在同一个类里方法间的直接相互调用

会导致加入的注解失效

解决方法:用如下方法,获取当前类的代理,再调用b方法,从而保证了代理流程被执行了。

public void a() {
    //业务逻辑处理
    A o =(A) AopContext.currentProxy();//获取当前类的代理
    o.b();
}

这里有一个错误写法,就是b方法一般抽出来的时候会写成private私有的,在IDEA中会提示你有问题的,但并不能告诉你问题在哪里,你执行的话

可能会导致NullPointerException空指针异常(如果没有用到Spring容器注入的对象倒是可以正常运行)。

正如最开始我所介绍的,Spring注入的对象,是加到拦截器维护的实例里了,你这里用多态的写法,调用的b方法,b作为私有方法根本无法继承,只能

调用父类的b方法,而这里的实例(代理类实例)根本就没有被注入容器管理的对象,它没有被赋值,就是个null,你只要调用了就直接NullPointerException。

解决方法:把private改掉,让子类可以继承方法。这样代多态的调用b方法,会走到代理类A'的b方法,然后进入正常代理流程,注解就生效了。问题得到解决

以上是我对问题的解析和解决方法,希望能帮助到你,也欢迎大佬们批评指导。

 
 
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值