在通知前后传递对象

Pass object between before and after advice

我的问题与 Pass object between before and after advice? 中的问题相同,但已接受的答案不适用于我的情况,我想就此主题寻求一些说明。

实际上,我正在使用 around 建议,但我必须更改它。让我们考虑一个例子:

public Object registerLog( ProceedingJoinPoint jpoint)
{
    SomeObject so = getSomeData( jpoint.getArgs());
    Object result = jpoint.proceed();
    getMoreData( result, so);
    log( so);
}

我的 proceed() 方法是将对象插入数据库。在这种情况下,我在事务提交之前记录了 INSERT 的结果,这不是很好。这就是为什么我想将 around 建议拆分为 beforeafter,这样当记录已经在数据库中时我可以登录 after。但是,在将对象存储到数据库之前,我仍然需要获取对象的一些数据。

当然,解决方案必须是线程安全的,所以我不能只向我的方面 class 添加一个 SomeObject 成员。从链接的问题中,我了解了 ThreadLocal,到目前为止,这是我找到的最佳解决方案。但是,我从来没有使用过它,我想问一下是否还有其他解决方案。也许有一种方法可以在处理某个方面时强制提交事务(我现在不确定这是否是个好主意)?

更新更多细节

我有两个切入点:

<aop:pointcut id="mngrPointcut" expression="execution(* com.mngr.Foo.*(..))"/>
<aop:pointcut id="savePointcut" expression="execution(* com.mngr.Foo.save(..))"/>

第一个切入点有建议

<aop:advisor advice-ref="txAdvice" pointcut-ref="mngrPointcut"/>

建议在哪里

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="select*,search*,get*" propagation="REQUIRED" rollback-for="Exception" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
    </tx:attributes>
</tx:advice>

对于第二个切入点,我有方面

<aop:aspect ref="logAspect">
    <aop:around method="registerLog" pointcut-ref="savePointcut"/>
</aop:aspect>

调用 com.mngr.Foo.save() 时,两个切入点均有效。可能因为声明顺序,先触发mngrPointcut,开始新的事务。然后savePointcut被触发,开始一个方面。正如我上面提到的,方面负责日志记录。由于触发切入点的顺序,对象在存储到数据库之前先被记录,这是错误的。我认为我必须使用 beforeafter 通知而不是 around,所以我可以在 after 部分调用 log() 方法,当交易已经完成时犯了。

如果您在方面优先级方面遇到问题,将切入点类型从 around 更改为 after 将无济于事。相反,您希望让方面实现 Ordered 接口或通过 @Order 对它们进行注解,两者均如 Spring AOP manual 中所述。还请在本章的下方搜索术语 "ordered",以便(没有双关语意)查看一些示例代码。

感谢 Nándor Előd Fekete 的评论,我通过设置交易顺序和建议解决了这个问题。较低阶的力方面 运行 较早进入和退出时相反。未排序的方面 运行 在有顺序的方面之后。