Migration application à utiliser Guice - comment injecter des transactions dans des objets existants?

StackOverflow https://stackoverflow.com/questions/951831

  •  11-09-2019
  •  | 
  •  

Question

Je suis nouveau à Guice, et je suis en train de travailler à une application avec une grande quantité de code existant. Il a plusieurs classes qui ressemblent à ceci:

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'
    }
}

Il est assez clair comment utiliser Guice pour lier les instances qui ne changent jamais, mais qu'en est-cas qui ne changent (à savoir les transactions)? Est-il possible pour moi d'utiliser Guice pour injecter une autre instance de transaction lorsqu'il change? Notez que l'instance de transaction n'est pas l'un des JPA / Hibernate / transactions de printemps bien pris en charge

Le moins invasive que je peux penser (en évitant la nécessité de migrer chaque classe qui utilise une transaction à la fois) utiliserait Guice pour injecter des transactions que lorsque instanciation d'objets, et je garderais le code d'application existant mises à jour opérations si nécessaire. Par exemple, ce fournisseur pourrait être utilisé pour injecter de nouveaux objets avec l'instance actuelle de 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;
    }
}

La logique d'application ressemblerait à quelque chose comme ceci:

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

Y at-il d'autres façons de mettre à jour l'instance de transaction que les classes existantes utilisent sans avoir à migrer chaque classe à la fois?

Était-ce utile?

La solution

Si je comprends bien, votre problème a deux parties indépendantes:

  1. en utilisant le droit par exemple de transaction sur les classes Guice-fiée
  2. en utilisant le droit par exemple de transaction sur les classes existantes.

Pour « 1 », votre fournisseur personnalisé fonctionne, mais je voudrais créer un champ personnalisé pour une transaction et lier la classe de transaction à ce champ d'application. Voir http://code.google.com/p/google-guice/wiki / CustomScopes pour obtenir des instructions sur les étendues personnalisées.

En ce qui concerne « 2 », une fois que vous avez un champ personnalisé, c'est le problème habituel d'utiliser Guice pour fournir des instances aux classes existantes. Vous n'avez pas mentionné le code qui fournit actuellement les instances de transaction aux classes existantes, mais vous pouvez simplement changer ce morceau de code particulier pour demander une instance de Guice. Puisque vous êtes, Guice prend soin de fournir l'instance à l'intérieur de votre « champ de transaction ».

Autres conseils

Jetez un oeil à assistée Injecter. Pour l'utiliser, définir une interface à trois lignes:

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

... puis utiliser un FactoryProvider liant pour lier l'usine:

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

Ensuite, vous pouvez injecter un DataAccessClassFactory où vous devez construire un DataAccessClass. AssistedInject est inclus dans Guice 2, même si elle nécessite un fichier .jar séparé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top