关于@Bean声明而不是类实现的春季@Transactional

2022-09-03 15:04:51

我想从我的Spring类中配置“事务性”bean,而不是用.@Configuration@Transactional

有点像老式的方式,从XML文件配置事务性建议,但不需要对我的类/方法名称的字符串引用来创建切入点。

原因是Bean实现在另一个代码库中,它所属的模块不依赖于Spring。阅读:我没有触及那颗豆子的源代码,只是实例化了它。该类是最终的,也无法扩展它以将Spring注释添加到子类。假设为了简单起见,所有方法都必须是事务性的。

豆子实现:

/** This class has no Spring dependency... */
// @Transactional <- which means I can't use this here
public final class ComplexComponentImpl implements ComplexComponent {

    private SomeRepository repo;

    public ComplexComponentImpl(SomeRepository repository) { this.repo = repository }

    public void saveEntities(SomeEntity e1, SomeEntity e2) {
        repo.save(e1);
        throw new IllegalStateException("Make the transaction fail");
    }

我想在我的配置类中做什么(在我的单元测试中不起作用):

@Configuration
@EnableTransactionManagement
public class ComplexComponentConfig {

    @Bean
    @Transactional // <- Make the bean transactional here
    public ComplexComponent complexComponent() {
        return new ComplexComponentImpl(repository());
    }

    // ...
}

事实上,上面的例子不起作用,因为在运行时没有任何东西是“事务性的”:即使抛出异常,实体也会持久化。e1

请注意,我的事务管理设置与标有 .@Transactional

问题:是否可以从类中声明 s 事务性,或者考虑到上述约束,是否有任何替代方案?@Bean@Configuration


答案 1

找到了一些内置的东西,这是@Mecon@Erik Gillespie的答案的总和,但样板有限。

Spring已经提供了一个TransportProxyFactoryBean,它只需在任何对象上设置一个事务代理。大部分设置可以重构为一些实用程序方法:

@Configuration
@EnableTransactionManagement
public class ComplexComponentConfig {

    /** NOT A @Bean, this object will be wrapped with a transactional proxy */
    public ComplexComponent complexComponentImpl() {
        return new ComplexComponentImpl(repository());
    }

    @Bean
    public ComplexComponent complexComponent() {
        TransactionProxyFactoryBean proxy = new TransactionProxyFactoryBean();

        // Inject transaction manager here
        proxy.setTransactionManager(txManager());

        // Define wich object instance is to be proxied (your bean)
        proxy.setTarget(complexComponentImpl());

        // Programmatically setup transaction attributes
        Properties transactionAttributes = new Properties();
        transactionAttributes.put("*", "PROPAGATION_REQUIRED");
        proxy.setTransactionAttributes(transactionAttributes);

        // Finish FactoryBean setup
        proxy.afterPropertiesSet();
        return (ComplexComponent) proxy.getObject;
    }

// ...
}

答案 2

我想你可能无法以这种方式使用@Transactional。Spring内置的后处理器之一,应该扫描具有该注释的所有类(bean),并相应地创建Aspect。

关于替代方案:我会为我必须使用的每个第三方类编写一个适配器类。然后让这些适配器类成为Spring Beans。


推荐