2009-06-04 6 views
8

Sono nuovo di Guice e sto lavorando a un'applicazione con una grande quantità di codice legacy. Ha diverse classi che assomigliano a questo:Migrazione dell'applicazione per utilizzare Guice - come iniettare le transazioni in oggetti esistenti?

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

E 'abbastanza chiaro come utilizzare Guice di legare le istanze che non cambiano mai, ma per quanto riguarda le istanze che cambiano (transazioni vale a dire)? C'è un modo per me di usare Guice per iniettare una diversa istanza di Transazione quando cambia? noti che l'istanza transazione non è una delle operazioni/primavera JPA/Hibernate ben supportato

L'approccio meno invasivo posso pensare (evitando la necessità di migrare ogni classe che utilizza una transazione immediatamente) userebbe Guice per iniettare Transaction solo durante l'istanziazione di oggetti, e manterrei il codice applicativo esistente che aggiorna le transazioni quando necessario. Ad esempio, questo provider potrebbe essere usato per iniettare nuovi oggetti con l'istanza corrente di transazione:

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

logica applicazione sarebbe simile a questa:

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

ci sono altri modi per aggiornare l'istanza di Transazione che le classi esistenti usano senza dover migrare ogni classe in una volta sola?

risposta

6

Se ho capito bene, il problema ha due parti indipendenti:

  1. utilizzando l'istanza di transazione giusta sulle classi Guice-cato
  2. utilizzando l'istanza di transazione giusta sulle classi precedenti.

Per "1", il provider personalizzato funziona, ma vorrei creare un ambito personalizzato per una transazione e associare la classe Transaction a tale ambito. Vedere http://code.google.com/p/google-guice/wiki/CustomScopes per istruzioni sugli ambiti personalizzati.

Per quanto riguarda "2", una volta che si dispone di un ambito personalizzato, questo è il solito problema dell'utilizzo di Guice per fornire istanze alle classi legacy. Non hai menzionato il codice che attualmente fornisce istanze Transaction alle classi legacy, ma potresti semplicemente modificare quel particolare pezzo di codice per richiedere un'istanza da Guice. Poiché sei all'interno del tuo "ambito di transazione", Guice si prende cura di fornire l'istanza giusta.

+0

Grazie - sembra che funzioni. Buon punto sul refactoring delle classi precedenti per richiedere Transazioni da Guice - sembra che sarebbe solo una piccola modifica per ogni classe legacy, e sarebbe probabilmente molto più semplice rispetto all'utilizzo di 2 sistemi per la gestione delle transazioni. –

1

Dai uno sguardo allo Assisted Inject. Per usarlo, definire un'interfaccia di tre righe:

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

... e quindi utilizzare un legame FactoryProvider di impegnare la fabbrica:

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

Poi si può iniettare un DataAccessClassFactory ovunque è necessario costruire a DataAccessClass. AssistedInject è incluso in Guice 2, anche se richiede un file .jar separato.

+0

Sembra che possa essere utile, ma non sto seguendo come posso utilizzarlo per aggiornare l'associazione della Transazione all'istanza che rappresenta la Transazione attualmente aperta. In altre parole: viene utilizzata una sola istanza di Transaction in qualsiasi momento, ma tale istanza viene sostituita ogni volta che viene avviata una nuova transazione. Esiste un esempio più dettagliato di utilizzo di AssistedInject da qualche parte?Nella pagina wiki, ho difficoltà a capire dove vengono istanziate le istanze di Data e Money. –

Problemi correlati