当@ActiveProfiles("test") 时,如何忽略特定方法的 spring @Transactional 注释
How can I ignore spring @Transactional annotation for a specific method when @ActiveProfiles("test")
我需要在集成测试期间忽略以下 @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)
}
}
问题是我所有的测试都是在默认情况下回滚的事务中执行的。当它在测试范围内 运行 允许它在事务内执行时,我怎么能忽略此方法的 @Transactional(propagation = Propagation.NEVER)
注释?
首先,您需要排除当前的 @EnableTransactionManagement
注释才能在您的 test
个人资料中激活。您可以通过将 @EnableTransactionManagement
注释隔离到一个单独的配置 class 来执行此操作,该配置排除了配置文件 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;
}
}
}
最后是您可以覆盖交易属性的部分。这个子classes ProxyTransactionManagementConfiguration
for AdviceMode.PROXY
,你需要一个基于AspectJTransactionManagementConfiguration
for 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
配置文件的配置 class 启用自定义事务管理配置。
@EnableCustomTransactionManagement(mode=AdviceMode.PROXY)
@Profile("test")
public class TransactionManagementTestConfig {}
希望对您有所帮助。
我需要在集成测试期间忽略以下 @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)
}
}
问题是我所有的测试都是在默认情况下回滚的事务中执行的。当它在测试范围内 运行 允许它在事务内执行时,我怎么能忽略此方法的 @Transactional(propagation = Propagation.NEVER)
注释?
首先,您需要排除当前的 @EnableTransactionManagement
注释才能在您的 test
个人资料中激活。您可以通过将 @EnableTransactionManagement
注释隔离到一个单独的配置 class 来执行此操作,该配置排除了配置文件 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;
}
}
}
最后是您可以覆盖交易属性的部分。这个子classes ProxyTransactionManagementConfiguration
for AdviceMode.PROXY
,你需要一个基于AspectJTransactionManagementConfiguration
for 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
配置文件的配置 class 启用自定义事务管理配置。
@EnableCustomTransactionManagement(mode=AdviceMode.PROXY)
@Profile("test")
public class TransactionManagementTestConfig {}
希望对您有所帮助。