小编典典

自定义Spring AOP左右+ @Transactional

java

我实现了一个自定义的“周围”以匹配自定义的“注释”。我希望周围的自定义可以在外部@Transactional中执行。不幸的是,这似乎不起作用。(AOP正在工作。我看到显示它的堆栈跟踪)。

堆栈跟踪显示我的AOP在(记录器)之前执行,MyBatis会话开始事务,MyBatis关闭事务,Spring关闭事务然后我的AOP完成。

我认为订购AOP实施工具会有所帮助。我将返回的值设置为1。这没用。我认为这是因为我误读了Spring的订单。

咨询订购

当多条建议都希望在同一连接点上运行时会发生什么?Spring
AOP遵循与AspectJ相同的优先级规则来确定建议执行的顺序。优先级最高的建议首先“在途中”运行(因此,给定两条优先建议,则优先级最高的建议首先运行)。从连接点“出路”中,优先级最高的建议将最后运行(因此,给定两条后置通知,优先级最高的建议将第二次运行)。

当在不同方面定义的两条建议都需要在同一连接点上运行时,除非您另外指定,否则执行顺序是不确定的。您可以通过指定优先级来控制执行顺序。通过在方面类中实现org.springframework.core.Ordered接口或使用Order批注对其进行注释,可以通过普通的Spring方法来完成。给定两个方面,从Ordered.getValue()(或注释值)返回较低值的方面具有较高的优先级。

当在相同方面定义的两条建议都需要在同一连接点上运行时,其顺序是未定义的(因为无法通过反射为javac编译的类检索声明顺序)。考虑将这些建议方法折叠为每个方面类中每个连接点的一个建议方法,或将建议重构为单独的方面类-
可以在方面级别进行排序。

所以我取出了order属性。这应该使@Transactional返回Integer.MIN_VALUE。因此,如果我理解上面的引用,它应该最后运行。当我重新部署时,它仍然向后执行。我的AOP,春季TX,MyBatis,关闭MyBatis,关闭SPring
Tx,关闭我的AOP。

我究竟做错了什么?


阅读 720

收藏
2020-11-16

共1个答案

小编典典

如果未为@Transactional注释配置order属性,则
负责事务属性的Advisor -
AbstractPointcutAdvisor
(实际上是它的子类之一)将返回Ordered
.LOWEST_PRECEDENCE,它被定义为Integer.MAX_VALUE。

负责自定义AOP通知的Advisor是同一AbstractPointcutAdvisor的子类,它将查看实际的Advice是否
实现Ordered接口,如果是,则在排序过程中将使用提供的值。如果自定义AOP通知未实现Ordered接口,则Advisor将返回相同的默认Ordered.LOWEST_PRECEDENCE,并且排序结果会变得
有些 不可预测。

因此,为@Transactional注释配置order属性,例如这样

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-3.1.xsd>
           .......

           <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" order="[Order for @Transactional]">
<beans/>

您的自定义AOP建议实施如下所示

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.springframework.core.Ordered;

@Aspect
public class CustomAspect implements Ordered {

    @Around(value = "@annotation(CustomAnnotation)")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    ... 
    }
    ....

    @Override
    public int getOrder() { 
        return [Order for @CustomAnnotation];
    }

    ....

}

那么您在整个应用程序中的排序就可能拥有所有的自由(但还是静态的)。

后台,是AspectJAwareAdvisorAutoProxyCreator在代理初始化时使用比较器org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator将Advisor排序,该排序器将排序委托给OrderComparator。后来,在实际执行后,AopProxy的具体实现为特定方法保存了一组建议,将其称为拦截器,并且我认为这可以用于动态重新排序,但是对我而言,这些东西似乎都不容易可访问和/或可配置的。

我的环境是Spring Beans,TX,AOP-所有版本4.0.3。我也有两个自定义的事务管理器,一个是Hibernate绑定的,一个是JDBC
DataSource绑定的,但是我认为这并不重要

2020-11-16