@ Транзакционный совет по аспектам возможен? - PullRequest
2 голосов
/ 08 апреля 2011

Можно ли применить тег @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>

Аспект с / pointcuts:

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() {};
}

Совет, который я пытаюсь применить к моим pointcuts:

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 ]

2 голосов
/ 08 апреля 2011

Ниже у меня есть пример, который показывает, как вы можете использовать @Transactional вместе с вашим inServiceLayer() 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? Вы должны отмечать только свои бизнес-методы, которые вы хотите выполнить в транзакции с этим.

Надеюсь, это поможет!

0 голосов
/ 26 сентября 2016

robgmills

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

Вы можете использовать выше совет Around, но нужно сделать пару небольших изменений.

  1. Добавить (propagation = Propagation.REQUIRES_NEW) к @Transactional в выше.
  2. Добавить @Transactional аннотацию к методу сервиса, для которого вы добавили pointcut inServiceLayer().
0 голосов
/ 14 июня 2016

Аннотация транзакции Spring во время выполнения создает прокси-объект. Таким образом, если вы применяете транзакционную аннотацию к совету, который консультирует службу, тогда транзакция будет для рекомендации, а не для службы, поскольку рекомендация работает на прокси-объекте службы, а ваша транзакционная аннотация будет работать на прокси-объекте совет, а не основной метод совета. В идеале у вас не должно быть совета, который является расширением функциональности сервиса. Это побеждает цель прокси-шаблона.

0 голосов
/ 12 апреля 2011

Как сказал @Espen, вы должны применять @Transactional непосредственно к своим бизнес-методам, так как сама аннотация заставляет Spring создать Aspect, который применяет транзакции к вашему методу.Поэтому нет необходимости создавать аспект вручную.

Однако, если вы хотите применить транзакции ко всем используемым вами методам обслуживания и всем остальным, что вы выбрали в этих точечных вызовах, вам следует использовать конфигурацию xml для создания транзакций. Ищите декларативное управление транзакциями в документации

Также я не думаю, что вы можете применить @Transactional к Совету.По крайней мере, это не работает для меня.

...