定制弹簧AOP + +交易

时间:2015-08-17 19:09:43

标签: java spring mybatis spring-aop

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

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

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

  

建议订购

     

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

     

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

     

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

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

我做错了什么?

3 个答案:

答案 0 :(得分:9)

如果没有为@Transactional注释配置订单属性,那么负责交易属性的Advisor - AbstractPointcutAdvisor (实际上,它的一个子类)将返回Ordered。LOWEST_PRECEDENCE,定义为Integer.MAX_VALUE。

负责自定义AOP建议的Advisor(同一AbstractPointcutAdvisor的子类)将查看实际的Advice是否实现Ordered接口,如果是,则在排序期间将使用提供的值。 如果自定义AOP建议未实现Ordered接口,则Advisor将返回相同的默认Ordered.LOWEST_PRECEDENCE,并且排序结果将略微不可预测。

因此,配置@Transactional注释的订单属性,例如像这样

<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绑定的,但我认为这不重要

答案 1 :(得分:3)

经过一些小试验后发现,只需删除订单属性就无法运行。我觉得这很奇怪,因为@Transactional默认订单是 Integer.MIN_VALUE 。显然,如果要启用排序,则必须将订单明确设置为所有AOP订单中的最小订单。

答案 2 :(得分:2)

从页面https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html开始,它表示交易的默认订单为System.setProperty("webdriver.ie.driver", "C:\\Utility\\BrowserDrivers\\IEDriverServer.exe"); DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS", true); capabilities.setCapability("ACCEPT_SSL_CERTS", true); capabilities.setCapability("SUPPORTS_ALERTS", true); capabilities.setCapability("UNEXPECTED_ALERT_BEHAVIOR", true); capabilities.setCapability("IE_ENSURE_CLEAN_SESSION", true); capabilities.setCapability("ENABLE_ELEMENT_CACHE_CLEANUP", true); capabilities.setCapability("nativeEvents", false); capabilities.setCapability("requireWindowFocus", false); capabilities.setJavascriptEnabled(true); capabilities.setCapability("ignoreProtectedModeSettings", true); InternetExplorerOptions opt = new InternetExplorerOptions(); opt.merge(capabilities); WebDriver driver = new InternetExplorerDriver(opt); ,其值等于Ordered.LOWEST_PRECEDENCE