【问题标题】:How can I ignore spring @Transactional annotation for a specific method when @ActiveProfiles("test")@ActiveProfiles("test") 时如何忽略特定方法的 spring @Transactional 注释
【发布时间】:2016-03-11 02:12:01
【问题描述】:

我需要在集成测试期间忽略以下 @Transactional 注释。

@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)
    }

}

问题是我所有的测试都是在默认回滚的事务中执行的。当此方法在测试范围内运行时 (@ActiveProfiles("test")) 允许它在事务中执行,我怎么能忽略 @Transactional(propagation = Propagation.NEVER) 注释?

【问题讨论】:

  • 您是否使用AdviceMode.PROXYAdviceMode.ASPECTJ 进行事务管理?
  • 我使用默认的AdviceMode.PROXY
  • 您想要实现的究竟是什么?换句话说,为什么您希望该方法在测试中的测试管理事务中运行,但在生产中的事务之外运行?

标签: java spring spring-transactions


【解决方案1】:

首先,您需要排除当前的@EnableTransactionManagement 注释才能在您的test 配置文件中处于活动状态。您可以通过将 @EnableTransactionManagement 注释隔离到一个单独的配置类来做到这一点,该配置类排除了配置文件 test,因此只有在 test 配置文件处于活动状态时才会激活它。

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

有了这些,我们就可以开始为您的测试配置文件构建自定义事务管理配置。首先我们定义一个注解,用于激活自定义事务管理(javadoc cmets 为示例的紧凑性而被剥离,详情参见EnableTransactionManagementjavadoc)。

@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 {}

我希望这会有所帮助。

【讨论】:

  • 我很高兴听到这个消息!
  • 有效!非常感谢!你保护了我的时间和思想 =))))
猜你喜欢
  • 1970-01-01
  • 2012-05-19
  • 2013-11-05
  • 2019-02-18
  • 2013-04-02
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
相关资源
最近更新 更多