自定义 Spring AOP Around + @Transactional
Custom Spring AOP Around + @Transactional
我实现了自定义 Around 以匹配自定义注释。我希望自定义在外部@Transactional 中执行。不幸的是,这似乎不起作用。 (AOP 正在运行。我看到显示它的堆栈跟踪)。
堆栈跟踪显示我的 AOP 在(记录器)之前执行,MyBatis 会话开始事务,MyBatis 关闭事务,Spring 关闭事务然后我的 AOP 完成。
我认为让我的 AOP 实现 Ordered 会有所帮助。我将值 returned 设置为 1。我使用 .这没有用。我认为这是因为我误读了 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. 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. Given two
aspects, the aspect returning the lower value from Ordered.getValue()
(or the annotation value) has the higher precedence.
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). 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.
所以我把order属性拿出来了。这应该使@Transactional return Integer.MIN_VALUE。所以,如果我理解上面的引述,最后应该是 运行。当我重新部署时,它仍然向后执行。我的AOP, Spring TX, MyBatis, 关闭MyBatis, 关闭SPring Tx, 关闭我的AOP.
我做错了什么?
经过一些试验后发现,简单地删除 order 属性并不能使这项工作成功。我觉得这很奇怪,因为 @Transactional 默认顺序是 Integer.MIN_VALUE。显然,如果你想启用排序,你必须明确地将订单设置为所有 AOP 订单中的最小订单。
如果没有为@Transactional注解配置order属性,那么Advisor which is responsible for transaction attribute - AbstractPointcutAdvisor
(其实是它的一个子类)会returnOrdered.LOWEST_PRECEDENCE,定义为Integer.MAX_VALUE.
负责自定义 AOP 通知的 Advisor,同一个 AbstractPointcutAdvisor 的子类,将查看实际 Advice 是否实现了 Ordered 接口,如果实现了,则在排序期间将使用提供的值.
如果自定义 AOP 通知未实现 Ordered 接口,Advisor return 具有相同的默认值 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 who upon a Proxy initialization sorts the Advisors using the comparator org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator which delegates the sorting to OrderComparator。
稍后,在实际执行时,AopProxy 的具体实现为特定方法保留了一组建议,它称之为拦截器,我猜这可能用于动态重新排序,但是 none 这些东西在我看来很容易获得 and/or 可配置。
我的环境是 Spring Beans、TX、AOP - 所有版本都是 4.0.3。我还有两个自定义事务管理器,一个是 Hibernate 绑定的,一个是 JDBC DataSource 绑定的,但我认为这里不重要
从页面 https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html ,它说交易的默认顺序是 Ordered.LOWEST_PRECEDENCE
,其值等于 Integer.MAX_VALUE
我实现了自定义 Around 以匹配自定义注释。我希望自定义在外部@Transactional 中执行。不幸的是,这似乎不起作用。 (AOP 正在运行。我看到显示它的堆栈跟踪)。
堆栈跟踪显示我的 AOP 在(记录器)之前执行,MyBatis 会话开始事务,MyBatis 关闭事务,Spring 关闭事务然后我的 AOP 完成。
我认为让我的 AOP 实现 Ordered 会有所帮助。我将值 returned 设置为 1。我使用 .这没有用。我认为这是因为我误读了 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. 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. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.
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). 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.
所以我把order属性拿出来了。这应该使@Transactional return Integer.MIN_VALUE。所以,如果我理解上面的引述,最后应该是 运行。当我重新部署时,它仍然向后执行。我的AOP, Spring TX, MyBatis, 关闭MyBatis, 关闭SPring Tx, 关闭我的AOP.
我做错了什么?
经过一些试验后发现,简单地删除 order 属性并不能使这项工作成功。我觉得这很奇怪,因为 @Transactional 默认顺序是 Integer.MIN_VALUE。显然,如果你想启用排序,你必须明确地将订单设置为所有 AOP 订单中的最小订单。
如果没有为@Transactional注解配置order属性,那么Advisor which is responsible for transaction attribute - AbstractPointcutAdvisor (其实是它的一个子类)会returnOrdered.LOWEST_PRECEDENCE,定义为Integer.MAX_VALUE.
负责自定义 AOP 通知的 Advisor,同一个 AbstractPointcutAdvisor 的子类,将查看实际 Advice 是否实现了 Ordered 接口,如果实现了,则在排序期间将使用提供的值. 如果自定义 AOP 通知未实现 Ordered 接口,Advisor return 具有相同的默认值 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 who upon a Proxy initialization sorts the Advisors using the comparator org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator which delegates the sorting to OrderComparator。 稍后,在实际执行时,AopProxy 的具体实现为特定方法保留了一组建议,它称之为拦截器,我猜这可能用于动态重新排序,但是 none 这些东西在我看来很容易获得 and/or 可配置。
我的环境是 Spring Beans、TX、AOP - 所有版本都是 4.0.3。我还有两个自定义事务管理器,一个是 Hibernate 绑定的,一个是 JDBC DataSource 绑定的,但我认为这里不重要
从页面 https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html ,它说交易的默认顺序是 Ordered.LOWEST_PRECEDENCE
,其值等于 Integer.MAX_VALUE