我有一个自定义周围实现匹配自定义注释。我希望自定义在外部@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。
我做错了什么?
答案 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