迁移应用程序以使用Guice - 如何将事务注入现有对象?

时间:2009-06-04 17:01:04

标签: transactions migration guice

我是Guice的新手,我正在使用大量遗留代码处理应用程序。它有几个类看起来像这样:

public final class DataAccessClass {

    private Transaction txn;

    @Inject //This was just added
    public DataAccessClass(/* injectable parameters */, Transaction txn) {

        this.txn = txn;
    }

    //Maybe add @Inject here to set a new transaction when it changes?
    public void setTransaction(Transaction txn) {

        this.txn = txn;
    }

    public void writeData(/* parameters for data to be written */) {

        //Write data using the current instance of 'txn'
    }
}

很明显如何使用Guice来绑定永不改变的实例,但是那些改变的实例(即事务)呢?有没有办法让我在改变时使用Guice注入不同的Transaction实例? 请注意,Transaction实例不是受到良好支持的JPA / Hibernate / Spring事务之一

我能想到的最少侵入性方法(避免需要同时迁移每个使用事务的类)将使用Guice仅在实例化对象时注入Transaction,并且我将保留现有的应用程序代码更新必要时进行交易。例如,此Provider可用于使用当前事务实例注入新对象:

public final class TransactionProvider implements Provider<Transaction> {

    /** Nullable transaction that should be used for all operations at the moment */
    private Transaction txn;

    public TransactionProvider(Transaction txn) {

        this.txn = txn;
    }

    /**
     * @param txn Nullable transaction to use for all operations at the moment
     */
    public void setTransaction(Transaction txn) {

        this.txn = txn;
    }

    /* Provider methods */

    public Transaction get() {

        return this.txn;
    }
}

应用程序逻辑看起来像这样:

public final class Application {

    private final Provider<Transaction> transactionProvider;
    private final DataAccessClass dao; //Instance provided by Guice

    public void scopedOperation() {

        //Use a fresh transaction for this operation
        final Transaction txn = ...;

        //Make transaction available to Guice (for new objects) and to legacy (already-instantiated) DAO classes
        this.transactionProvider.setTransaction(txn);
        this.dao.setTransaction(txn); //Legacy approach - can this be updated?

        //Do some kind of data operation under the scope of the current transaction
        try {
            this.dao.writeData(...);
        } catch (Exception e) {
            txn.abort();
            throw new RuntimeException("Operation failed", e);
        }

        //The operation is over now
        this.txn.commit();
    }

是否还有其他方法可以更新现有类使用的Transaction实例,而无需一次迁移每个类?

2 个答案:

答案 0 :(得分:6)

如果我理解正确,你的问题有两个独立的部分:

  1. 在Guice-fied classes上使用正确的Transaction实例
  2. 在旧类上使用正确的事务实例。
  3. 对于'1',您的自定义提供程序可以正常工作,但我会为事务创建自定义范围并绑定该范围内的Transaction类。有关自定义范围的说明,请参阅http://code.google.com/p/google-guice/wiki/CustomScopes

    关于“2”,一旦有了自定义范围,这就是使用Guice为遗留类提供实例的常见问题。您没有提到当前为遗留类提供事务实例的代码,但您可以更改该特定代码段以从Guice请求实例。由于您在“交易范围”内,Guice负责提供正确的实例。

答案 1 :(得分:1)

看看Assisted Inject。要使用它,请定义一个三行界面:

public interface DataAccessClassFactory {
  DataAccessClass create(Transaction transaction);
}

...然后使用FactoryProvider绑定来绑定工厂:

bind(DataAccessClassFactory.class).toProvider(
    FactoryProvider.newFactory(DataAccessClassFactory.class, DataAccessClass.class));

然后,您可以在构建DataAccessClassFactory的任何位置注入DataAccessClass。 AssistedInject包含在Guice 2中,虽然它需要一个单独的.jar文件。