8

私は 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 トランザクションの 1 つではないことに注意してください。

私が考えることができる最も侵襲性の低いアプローチ (トランザクションを使用するすべてのクラスを一度に移行する必要を回避する) は、Guice を使用して、オブジェクトをインスタンス化するときにのみ Transaction を注入し、必要に応じてトランザクションを更新する既存のアプリケーション コードを保持します。 . たとえば、このプロバイダを使用して、トランザクションの現在のインスタンスで新しいオブジェクトを挿入できます。

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 のインスタンスを更新する他の方法はありますか?

4

2 に答える 2

6

私がこれを正しく理解していれば、問題には 2 つの独立した部分があります。

  1. Guice-fied クラスで適切な Transaction インスタンスを使用する
  2. レガシー クラスで適切な Transaction インスタンスを使用する。

'1' の場合、カスタム プロバイダーは機能しますが、トランザクションのカスタム スコープを作成し、そのスコープで Transaction クラスをバインドします。カスタム スコープの手順については、 http://code.google.com/p/google-guice/wiki/CustomScopesを参照してください。

'2' に関しては、カスタム スコープを取得すると、これは Guice を使用してレガシー クラスにインスタンスを提供する際の通常の問題です。レガシー クラスに現在 Transaction インスタンスを提供しているコードについては触れていませんが、特定のコードを変更して、Guice からインスタンスを要求することができます。「トランザクション スコープ」内にいるため、Guice は適切なインスタンスを提供します。

于 2009-06-06T11:32:35.563 に答える
1

Assisted Inject をご覧ください。これを使用するには、3 行のインターフェイスを定義します。

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

...そして、FactoryProviderバインディングを使用してファクトリをバインドします。

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

DataAccessClassFactory次に、を構築する必要がある場所に a を注入できますDataAccessClass。AssistedInject は Guice 2 に含まれていますが、別の .jar ファイルが必要です。

于 2009-06-05T01:32:53.933 に答える