@Transactional可以提供方面建议吗?

时间:2011-04-07 22:15:31

标签: spring transactions aop aspectj

我可以将@Transactional标记应用于方面建议吗?我正在尝试使用方面将所有调用包装到服务层(com.mycompany.app.myapp.service。*)中。我的方面是正确拦截对服务层的调用,但我无法弄清楚如何启动事务。我以为我可以应用@Transactional标签,因为我有标签,它会把它拿起并开始交易。我错过了什么?

XML配置:     

<bean id="systemArchitectureAspect" class="com.mycompany.app.myapp.aspect.SystemArchitecture"/>
<bean id="transactionAspect" class="com.mycompany.app.myapp.aspect.MyAspect"/>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"  
    class="org.springframework.transaction.jta.JtaTransactionManager"> 
    <property name="transactionManager" ref="AtomikosTransactionManager" /> 
    <property name="userTransaction" ref="AtomikosUserTransaction" /> 
</bean> 

<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"  
    init-method="init" destroy-method="close"> 

    <property name="forceShutdown" value="false" /> 
</bean> 

<bean id="AtomikosUserTransaction"  
    class="com.atomikos.icatch.jta.UserTransactionImp"> 
    <property name="transactionTimeout" value="10" />
</bean> 

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

具有切入点的方面:

package com.mycompany.app.myapp.aspect;

@Aspect
public class SystemArchitecture {
    @Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
    public void inServiceLayer() {};

    @Pointcut( "execution(* com.mycompany.data..*.*(..))" )
    public void inDataAccessLayer() {};
}

我正在尝试应用于我的切入点的建议:

package com.mycompany.app.myapp.aspect;

@Aspect
public class TransactionAspect {

    @Transactional
    @Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
    public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
    {
        return pjp.proceed();
    }
}

4 个答案:

答案 0 :(得分:2)

下面我有一个示例,说明如何将@TransactionalinServiceLayer() Pointcut一起使用。我选择将正常流与异常流分开。这就是我不使用@Around建议的原因。

@Aspect
public class TransactionAspect {
    private TransactionService transactionService = new TransactionServiceNull();

    @Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
    public void inServiceLayer() {};

    @Pointcut("execution(@org.springframework.transaction.annotation
        .Transactional * *(..))")
    public void transactionalMethod() {}

    @Before("transactionalMethod() && inServiceLayer()")
    public void beforeTransactionalMethod(JoinPoint joinPoint) {
        transactionService.beginTransaction();
    }

    @AfterReturning("transactionalMethod() && inServiceLayer()")
    public void afterTransactionalMethod(JoinPoint joinPoint) {
        transactionService.commit();
    }

    @AfterThrowing(pointcut = "transactionalMethod() && inServiceLayer()", 
         throwing = "e")
    public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint, 
         RuntimeException e) {
        transactionService.rollback();
    }

    public void setTransactionService(
        final TransactionService transactionService) {
        this.transactionService = transactionService;
    }
}

快速浏览一下代码后,我不得不问你为什么要用Pointcut注明@Transactional?您应该只标记要在事务中执行的业务方法。

我希望这有帮助!

答案 1 :(得分:0)

正如@Espen所说,您应该直接对业务方法应用@Transactional,因为Annotation本身会导致Spring创建一个将事务应用于您的方法的Aspect。因此无需手动创建方面。

但是,如果要将事务应用于所有服务方法以及使用这些切入点选择的其他任何内容,则应使用xml配置来创建事务。 Look for declarative transaction management in the documentation

此外,我认为您不能将@Transactional应用于建议。至少它不适合我。

答案 2 :(得分:0)

运行时的Spring事务注释创建一个代理对象。因此,如果您在建议服务的建议上应用事务性注释,那么事务将用于建议而不是服务,因为该建议适用于服务的代理对象,并且您的事务注释可以在该服务的代理对象上工作。建议而不是建议的主要方法。理想情况下,您不应该获得有关服务功能扩展的建议。这违背了代理模式的目的。

答案 3 :(得分:0)

robgmills

   @Transactional
    @Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
    public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
    {
        return pjp.proceed();
    }

你可以使用上面的建议,但需要做一些小改动。

  1. (propagation = Propagation.REQUIRES_NEW)添加到@Transactional 在上面。
  2. @Transactional注释添加到已添加了切入点inServiceLayer()的服务方法。