简体   繁体   English

定制弹簧AOP周围+ @Transactional

[英]Custom Spring AOP Around + @Transactional

I have a custom Around implemented to match on a custom Annotation. 我有一个自定义周围实现匹配自定义注释。 I want the custom around to execute WITHIN the outer @Transactional. 我希望自定义在外部@Transactional中执行。 Unfortunately, this doesn't appear to work. 不幸的是,这似乎不起作用。 (The AOP is working. I see stacktraces that show it). (AOP正在工作。我看到展示它的堆栈跟踪)。

The stack traces show my AOP executing before (a logger), the MyBatis Session starting a transaction, MyBatis closing the Transactions, Spring closing the transaction and then my AOP completing. 堆栈跟踪显示我的AOP执行之前(记录器),MyBatis会话启动事务,MyBatis关闭事务,Spring关闭事务,然后我的AOP完成。

I thought having my AOP implement Ordered would help. 我认为让我的AOP工具Ordered会有所帮助。 I set the value returned to 1. I used . 我将返回的值设置为1.我用过。 This didn't work. 这没用。 I think it's because I misread how Spring orders. 我想这是因为我误读了Spring的命令。

Advice ordering 建议订购

What happens when multiple pieces of advice all want to run at the same join point? 当多条建议都想在同一个连接点运行时会发生什么? Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. Spring AOP遵循与AspectJ相同的优先级规则来确定建议执行的顺序。 The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first). 最高优先级的建议首先“在路上”(所以给出两条之前的建议,优先级最高的建议先运行)。 "On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second). 从连接点“出路”,最高优先级建议最后运行(因此,给出两条后建议,具有最高优先级的建议将运行第二)。

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. 当在不同方面定义的两条建议都需要在同一个连接点运行时,除非您另行指定,否则执行顺序是未定义的。 You can control the order of execution by specifying precedence. 您可以通过指定优先级来控制执行顺序。 This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. 这是通过在方法类中实现org.springframework.core.Ordered接口或使用Order注释对其进行注释来以常规Spring方式完成的。 Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence. 给定两个方面,从Ordered.getValue()(或注释值)返回较低值的方面具有较高的优先级。

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). 当在同一方面定义的两条建议都需要在同一个连接点上运行时,排序是未定义的(因为没有办法通过反射为javac编译的类检索声明顺序)。 Consider collapsing such advice methods into one advice method per join point in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level. 考虑将这些建议方法折叠到每个方面类中每个连接点的一个建议方法中,或者将这些建议重构为单独的方面类 - 可以在方面级别进行排序。

So I took out the order attribute. 所以我拿出了order属性。 This should make @Transactional return Integer.MIN_VALUE. 这应该使@Transactional返回Integer.MIN_VALUE。 So it should, if I understood the quote above, run last. 因此,如果我理解上面的引用,它应该运行到最后。 When I redeployed, it still executed backward. 当我重新部署时,它仍然向后执行。 My AOP, Spring TX, MyBatis, Close MyBatis, Close SPring Tx, Close My AOP. 我的AOP,Spring TX,MyBatis,关闭MyBatis,关闭SPring Tx,关闭我的AOP。

What am I doing wrong? 我究竟做错了什么?

If the order attribute is not configured for @Transactional annotation, then the Advisor which is responsible for transaction attribute - AbstractPointcutAdvisor (in fact, one of the subclasses of it) will return Ordered .LOWEST_PRECEDENCE, which is defined as Integer.MAX_VALUE. 如果订单属性未配置为@Transactional注解,那么顾问 ,负责事务属性- AbstractPointcutAdvisor (事实上,它的子类之一)将返回有序 .LOWEST_PRECEDENCE,它被定义为Integer.MAX_VALUE的。

The Advisor which is responsible for custom AOP advice, a subclass of the same AbstractPointcutAdvisor, will look whether the actual Advice implements Ordered interface, and if it does, the provided value will be used during the sorting. 负责自定义AOP建议的Advisor是同一AbstractPointcutAdvisor的子类,它将查看实际的Advice是否实现了Ordered接口,如果是,则在排序期间将使用提供的值。 If custom AOP advice does not implement Ordered interface, the Advisor returns the same default Ordered.LOWEST_PRECEDENCE and the result of the sorting becomes slightly unpredictable. 如果自定义AOP建议未实现Ordered接口,则Advisor返回相同的默认Ordered.LOWEST_PRECEDENCE,并且排序结果变得有些不可预测。

So, configuring the order attribute for @Transactional annotation eg like this 因此,为@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/>    

and your custom AOP advice implementation looks like this 并且您的自定义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];
    }

    ....

}

then you probably have all the freedom (yet, statically) with the ordering throughout your application. 然后你可能拥有整个应用程序中的排序的所有自由(但静态)。

Under the hood, it's AspectJAwareAdvisorAutoProxyCreator who upon a Proxy initialization sorts the Advisors using the comparator org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator which delegates the sorting to OrderComparator . 幕后 ,它是AspectJAwareAdvisorAutoProxyCreator ,它在代理初始化时使用比较器org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator对Advisors进行排序,该比较器将排序委托给OrderComparator Later on, upon the actual execution, a concrete implementation of AopProxy holds for a specific method an array of the advices, whom it calls interceptors, and this might be used for dynamic reordering, I guess, but none of these things seems to me easily accessible and/or configurable. 稍后,在实际执行时, AopProxy的具体实现为特定方法提供了一个建议数组,它称之为拦截器,这可能用于动态重新排序,我猜,但这些东西都不容易在我看来可访问和/或可配置。

My environment is Spring Beans, TX, AOP - all version 4.0.3. 我的环境是Spring Beans,TX,AOP - 所有版本4.0.3。 I also have two custom Transaction Managers, one is Hibernate-bound and one is JDBC DataSource-bound, but I don't think it matters here 我还有两个自定义事务管理器,一个是Hibernate绑定的,一个是JDBC DataSource绑定的,但我认为这不重要

After a little experimenting it turns out that simply removing the order attribute does not make this work. 经过一些实验后发现,简单地删除订单属性并不能使其工作。 I find this odd as the @Transactional default order is Integer.MIN_VALUE . 我觉得这很奇怪,因为@Transactional默认顺序是Integer.MIN_VALUE Apparently if you want to enable ordering you have to explicitly set the order to the smallest of all the AOP orders. 显然,如果要启用排序,则必须将订单明确设置为所有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