繁体   English   中英

定制弹簧AOP周围+ @Transactional

[英]Custom Spring AOP Around + @Transactional

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

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

我认为让我的AOP工具Ordered会有所帮助。 我将返回的值设置为1.我用过。 这没用。 我想这是因为我误读了Spring的命令。

建议订购

当多条建议都想在同一个连接点运行时会发生什么? Spring AOP遵循与AspectJ相同的优先级规则来确定建议执行的顺序。 最高优先级的建议首先“在路上”(所以给出两条之前的建议,优先级最高的建议先运行)。 从连接点“出路”,最高优先级建议最后运行(因此,给出两条后建议,具有最高优先级的建议将运行第二)。

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

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

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

我究竟做错了什么?

如果订单属性未配置为@Transactional注解,那么顾问 ,负责事务属性- AbstractPointcutAdvisor (事实上,它的子类之一)将返回有序 .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对Advisors进行排序,该比较器将排序委托给OrderComparator 稍后,在实际执行时, AopProxy的具体实现为特定方法提供了一个建议数组,它称之为拦截器,这可能用于动态重新排序,我猜,但这些东西都不容易在我看来可访问和/或可配置。

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

经过一些实验后发现,简单地删除订单属性并不能使其工作。 我觉得这很奇怪,因为@Transactional默认顺序是Integer.MIN_VALUE 显然,如果要启用排序,则必须将订单明确设置为所有AOP订单中的最小订单。

从页面https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html ,它表示事务的默认顺序是Ordered.LOWEST_PRECEDENCE ,其值等于Integer.MAX_VALUE

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM