Spring @Transactional on @Bean声明而不是class Implementation

时间:2015-04-24 16:58:55

标签: java spring jpa transactions

我想配置" transactional"来自我的Spring @Configuration类的bean,而不是使用@Transactional注释类实现本身。

有点像旧学校的方式,从XML文件配置事务建议,但不需要对我的类/方法名称的String引用来创建切入点。

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

bean实现:

/** 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());
    }

    // ...
}

上面的例子实际上并没有起作用,因为没有任何事情可以解决问题&#34;事务性的&#34;在运行时:即使抛出异常,实体e1也会被持久化。

请注意,我的事务管理设置适用于标有@Transactional的实现类。

问题:是否可以从@Bean类声明@Configuration的事务处理,或者是否有任何其他方法考虑上述约束?

3 个答案:

答案 0 :(得分:8)

找到内置的内容,即@Mecon@Erik Gillespie的答案之和,并且有限的样板。

Spring已经提供了TransactionProxyFactoryBean,只需在任何对象上设置事务代理。许多设置可以重构为某种实用方法:

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

// ...
}

答案 1 :(得分:1)

我认为你可能不会以这种方式使用@Transactional。 Spring的内置PostProcessors之一,应该扫描具有该注释的所有类(bean),并相应地创建Aspects。

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

答案 2 :(得分:1)

您不能以这种方式使用@Transactional,但您可以使用Spring以编程方式配置方面。

用于以编程方式定义方面的Spring文档:

  1. http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aspectj-programmatic
  2. http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html
  3. 文档中的示例非常简单。定义事务方面可能会更复杂,如果您发现使用基于XML的代理的便利性或者采用@Mecon的建议并编写适配器,我不会感到惊讶。