用源码带你看懂SpringAOP及事物失效和事物的传播行为!

      OK,大家好,想必玩JAVA的应该都玩过Spring,它是一款非侵入,一站式的一种框架,提供了非常多的功能,其中AOP为Spring框架的一大特色,好了人帅话不多,直接进入正题,今天探讨以下几个问题!

      (1). SpringAOP如何工作?

      (2). SpringAOP用作声明式事务时,事务何时会失效?

       (3).SpringAOP的用作声明式事务时,事务的传播行为为什么会是非事务方法在事务方法中会使用当前事务方法的事务,如果新开事物为什么又会脱离当前事务呢?

       OK,那么我们就从第一个问题开始讨论起: SpringAOP如何工作?

   好的我们都知道SpringAOP需要声明切面,切点,通知,连接点,这里我解释一下这几个概念。

   切面:比如需要在业务方法上添加日志逻辑,我们为了保持业务方法的干净,不想在业务方法里面添加这些逻辑,于是可以将这些日志逻辑拿出来放到一个独立的类中,并放在类中的成员方法中。

  通知:正如上面所说,我们把日志逻辑拿出来放到方法中,必然有在业务方法的前面运行日志,在业务方法的后面运行日志,在业务方法出错抛异常的时候运行日志。也就对应了那几个SpringAOP的通知。

  连接点:连接点就是目标方法的一些信息(也可以说就是目标方法),我们必然将他们切分到不同的类的时候还要与我的目标方法产生联系,必然需要连接点来提供一些我们打印日志的信息。

切点:就是那些业务方法需要用到我的日志逻辑。

   OK,这里我们再来串一下,切面提供了对业务方法额外的功能,切面里面的通知则是具体的功能实现,以及与连接点(即目标方法)的连接方式(即before,after等连接方式),以上最终靠切点应用。这就是Spring的AOP(面向切面编程),就是将原来耦合在一切的功能,拆分成独立的功能,拆分后如何建立关系起调用关系。

   下面我们通过源码来具体看一下:

       首先切面里面的各种通知其实质就是代表了一个一个方法拦截器,而这些方法拦截器通过实现此接口来完成调用切面通知方法的功能,查看关系我们可以看出

这几种方法拦截器就对应了我们的通知的几种形式,就是靠这几种方法拦截器最终调用的我们的切面里面的通知方法,我们看一下那它又是如何与目标方法产生联系的呢?

当目标方法被代理对象拦截到invoke方法里面时,取得到该目标方法所应用的通知拦截器,取得后最终会去调用上面这个类的 procees()方法,下面是这个方法的实现



然后通过调用拦截器的invoke方法(里面去调用切面的相关通知方法)最终回调到这个proceed方法里面,可以使得当前的拦截器的索引满足

这个的时候去判断里面调用目标方法。这里便是整个AOP调用切面已经目标方法的流程,希望大家通过源码去好好理解!

 

  (2).SpringAOP用作声明式事务时,事务何时会失效?

 当SpringAOP做声明式事务的时候考虑事物如何会失效,这里直接给出结论: 当调用非事物方法时且非事物方法内部包含事务方法时会造成事务失效,具体原因用源码来展示!

当进入代理对象入口时:


他首先会获得该方法的拦截器链,如果该方法没有被任何拦截器所拦截(即非事务方法时),他就会直接反射调用目标方法

因此这个时候就没有开启事务故事物会失效,这就是从源码分析所得来的。  

 (3).SpringAOP的用作声明式事务时,事务的传播行为为什么会是非事务方法在事务方法中会使用当前事务方法的事务,如果新开事物为什么又会脱离当前事务呢?

好的上面将了事务失效的逻辑,那么下面将事务正常应用的逻辑:去调用procced方法进入事物逻辑


 最终里面他会调用这个 拦截器的invoke方法里面去调用

这个方法从名字上我们也已经看出来了调用目标方法包含事务,点进去后


重点来了由上图我们可以看出SpringAOP做声明式事物的所以逻辑,其实这个方法相当于我们学的环绕通知.

 OK,看到这里就可以解释事物的传播行为了

    (1)在事物方法中,非事务方法也会运用到当前事务,原因就是你已经处在我的事务逻辑里面了。

     (2)那为什么事务方法中的事务方法会应用与当前事务呢?

      OK,我们点开事务提交方法commitTransactionAfterReturning(txInfo);


从这句代码里面可以看出当前事物的状态标识是新事务的时候,才可以做提交,而非新事务时,会延迟提交。这就是为什么事务方法中的事务方法会应用与当前事务的原因,因为当内部事务方法运行完成后会造成延迟提交,因为它的事务状态是旧的嘛,应用与我当前的事物。而如果你新开一个事物的话,那么你内部事务方法的事务状态是新的可以立即提交,需要等我外层方法执行完之后在进行提交。

 ***OK,将到这里说一个重点,一个类只会有一种事务运行方式,意思就是当你的事务方法内部调用了一个新开事务的方法时,用的还是同一个事务,原因是你在这个方法中调用本类方法时它并非是代理对象调用,而是你真正被代理的对象调用的方法,所以它不会进入新的一个被代理对象拦截方法的一个过程,就会呆在你外层的这个方法的事务当中,也就相当于事务失效,这也是事务失效的第二种情况,那么怎么解决呢?既然说到了你的内部方法不是代理对象调用的而是你被代理对象调用的,那么你可以将你的这个方法放到外部类里面,或者在本类的成员变量中注入一个本类的对象,那么此时获得的就是代理对象,在调用的话他就会在进一层事务的逻辑了。

    OK,说了这么多,希望对大家对AOP的认识能有所加深!

      




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值