[英]How can I ignore spring @Transactional annotation for a specific method when @ActiveProfiles(“test”)
I need to ignore the following @Transactional
annotation during my integration tests. 在集成测试期间,我需要忽略以下
@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)
}
}
The problem is that all my tests are executed inside a transaction that is rolled back by default. 问题是我的所有测试都是在默认情况下回滚的事务中执行的。 How could I ignore the
@Transactional(propagation = Propagation.NEVER)
annotation for this method when it is running in the scope of a test ( @ActiveProfiles("test")
) allowing it to be executed inside a transaction? 当该方法在测试范围内运行时(
@ActiveProfiles("test")
)允许它在事务内执行时,我怎么能忽略该方法的@Transactional(propagation = Propagation.NEVER)
注释?
First of all, you need to exclude your current @EnableTransactionManagement
annotation to be active in your test
profile. 首先,您需要将当前的
@EnableTransactionManagement
注释排除在test
配置文件中。 You can do this by isolating the @EnableTransactionManagement
annotation to a separate configuration class which excludes the profile test
so it only gets activated whenever the test
profile is not active. 您可以通过将
@EnableTransactionManagement
批注隔离到单独的配置类来完成此操作,该配置类排除了配置文件test
因此只有在test
配置文件不活动时才会激活它。
@EnableTransactionManagement(mode=AdviceMode.PROXY)
@Profile("!test")
public class TransactionManagementConfig {}
With that in place, we can start building up the custom transaction management configuration for your test profile. 有了这些,我们就可以开始为您的测试配置文件构建自定义事务管理配置。 First we define an annotation that will be used to activate custom transaction management (javadoc comments stripped for compactness of the example, see
EnableTransactionManagement
javadoc for details). 首先,我们定义一个将用于激活自定义事务管理的注释(为示例的紧凑性剥离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;
}
Then we need an import selector. 然后我们需要一个导入选择器。 Note, that since you're using
AdviceMode.PROXY
, i skipped implementing the ASPECTJ
part, but that should be done analogously in order to use AspectJ based transaction management. 请注意,由于您正在使用
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;
}
}
}
And finally the part where you will be able to override the transaction attributes. 最后,您将能够覆盖事务属性的部分。 This one subclasses
ProxyTransactionManagementConfiguration
for AdviceMode.PROXY
, you would need an analogous implementation based on AspectJTransactionManagementConfiguration
for AdviceMode.ASPECTJ
. 这一个子类
ProxyTransactionManagementConfiguration
为AdviceMode.PROXY
,则需要基于类似的实现AspectJTransactionManagementConfiguration
为AdviceMode.ASPECTJ
。 Feel free to implement your own logic, whether be it a constant override of whatever attributes the original AnnotationTransactionAttributeSource
would determine as in my example, or going to greater lengths by introducing and handling your own custom annotation for this purpose. 随意实现您自己的逻辑,无论是原始
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;
}
};
}
}
Finally, you'll need to enable the custom transaction management configuration with a configuration class tied to the test
profile. 最后,您需要使用与
test
配置文件绑定的配置类启用自定义事务管理配置。
@EnableCustomTransactionManagement(mode=AdviceMode.PROXY)
@Profile("test")
public class TransactionManagementTestConfig {}
I hope this helps. 我希望这有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.