2016-03-09 2 views
2

Мне нужно игнорировать следующую аннотацию @Transactional во время моих интеграционных тестов.Как я могу игнорировать примечание весны @Transactional для конкретного метода, когда @ActiveProfiles («test»)

@Service 
public class MyClass { 

    @Transactional(propagation = Propagation.NEVER) 
    public void doSomething() { 
     // do something that once in production can not be inside a transaction (reasons are omitted) 
    } 

} 

Проблема в том, что все мои тесты выполняются внутри транзакции, которая откатывается по умолчанию. Как я могу игнорировать аннотацию @Transactional(propagation = Propagation.NEVER) для этого метода, когда он запущен в рамках теста (@ActiveProfiles("test")), разрешающего его выполнять внутри транзакции?

+0

Вы используете 'AdviceMode.PROXY' или' AdviceMode.ASPECTJ' для управления транзакциями? –

+0

Я использую по умолчанию 'AdviceMode.PROXY' – vhtc

+0

. Что именно вы пытаетесь достичь? Другими словами, почему вы хотите, чтобы этот метод выполнялся в тестовой транзакции в тестах, но за пределами транзакции в производстве? –

ответ

1

Прежде всего, вы должны исключить свою текущую аннотацию @EnableTransactionManagement, которая будет активной в вашем профиле test. Вы можете сделать это, выделив аннотацию @EnableTransactionManagement на отдельный класс конфигурации, который исключает профиль test, поэтому он активируется только тогда, когда профиль test равен , а не.

@EnableTransactionManagement(mode=AdviceMode.PROXY) 
@Profile("!test") 
public class TransactionManagementConfig {} 

С помощью этого на месте мы можем приступить к созданию пользовательской конфигурации управления транзакциями для вашего тестового профиля. Сначала мы определяем аннотацию, которая будет использоваться для активации пользовательского управления транзакциями (комментарии javadoc, снятые для компактности примера, см. В разделе EnableTransactionManagement javadoc).

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Import(CustomTransactionManagementConfigurationSelector.class) 
public @interface EnableCustomTransactionManagement { 
    boolean proxyTargetClass() default false; 
    AdviceMode mode() default AdviceMode.PROXY; 
    int order() default Ordered.LOWEST_PRECEDENCE; 
} 

Тогда нам нужен импортный селектор. Обратите внимание, что, поскольку вы используете AdviceMode.PROXY, я пропустил реализацию части ASPECTJ, но это должно быть сделано аналогичным образом, чтобы использовать управление транзакциями на основе AspectJ.

public class CustomTransactionManagementConfigurationSelector extends 
     AdviceModeImportSelector<EnableCustomTransactionManagement> { 
    @Override 
    protected String[] selectImports(AdviceMode adviceMode) { 
     switch (adviceMode) { 
     case PROXY: 
      return new String[] { 
       AutoProxyRegistrar.class.getName(), 
       CustomTransactionAttributeSourceConfig.class.getName() 
      }; 
     case ASPECTJ: 
     default: 
      return null; 
     } 
    } 
} 

И, наконец, часть, в которой вы сможете переопределить атрибуты транзакции. В этом подклассе ProxyTransactionManagementConfiguration для AdviceMode.PROXY вам понадобится аналогичная реализация на основе AspectJTransactionManagementConfiguration для AdviceMode.ASPECTJ. Не стесняйтесь реализовать свою собственную логику, будь то постоянное переопределение любых атрибутов, которые исходный AnnotationTransactionAttributeSource определял бы, как в моем примере, или увеличивая длину, путем введения и обработки вашей собственной аннотации для этой цели.

@Configuration 
public class CustomTransactionAttributeSourceConfig 
     extends ProxyTransactionManagementConfiguration { 

    @Override 
    public void setImportMetadata(AnnotationMetadata importMetadata) { 
     this.enableTx = AnnotationAttributes 
       .fromMap(importMetadata.getAnnotationAttributes(
         EnableCustomTransactionManagement.class.getName(), 
         false)); 
     Assert.notNull(this.enableTx, 
       "@EnableCustomTransactionManagement is not present on importing class " 
         + importMetadata.getClassName()); 
    } 

    @Bean 
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 
    @Override 
    public TransactionAttributeSource transactionAttributeSource() { 
     return new AnnotationTransactionAttributeSource() { 

      private static final long serialVersionUID = 1L; 

      @Override 
      protected TransactionAttribute findTransactionAttribute(
        Class<?> clazz) { 
       TransactionAttribute transactionAttribute = 
         super.findTransactionAttribute(clazz); 
       if (transactionAttribute != null) { 
        // implement whatever logic to override transaction attributes 
        // extracted from @Transactional annotation 
        transactionAttribute = new DefaultTransactionAttribute(
          TransactionAttribute.PROPAGATION_REQUIRED); 
       } 
       return transactionAttribute; 
      } 

      @Override 
      protected TransactionAttribute findTransactionAttribute(
        Method method) { 
       TransactionAttribute transactionAttribute = 
         super.findTransactionAttribute(method); 
       if (transactionAttribute != null) { 
        // implement whatever logic to override transaction attributes 
        // extracted from @Transactional annotation 
        transactionAttribute = new DefaultTransactionAttribute(
          TransactionAttribute.PROPAGATION_REQUIRED); 
       } 
       return transactionAttribute; 
      } 
     }; 
    } 
} 

Наконец, вам необходимо включить конфигурацию управления пользовательских транзакций с классом конфигурации, привязанной к test профилю.

@EnableCustomTransactionManagement(mode=AdviceMode.PROXY) 
@Profile("test") 
public class TransactionManagementTestConfig {} 

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

+0

Люблю тебя, мужик! Работайте как шарм! – vhtc

+0

Я рад это слышать! –

Смежные вопросы