代码之家  ›  专栏  ›  技术社区  ›  Kyle Krull

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

  •  8
  • Kyle Krull  · 技术社区  · 16 年前

    我对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来注入不同的事务实例? 请注意,事务实例不是受良好支持的JPA/Hibernate/Spring事务之一。

    我能想到的最不具入侵性的方法(避免一次性迁移每个使用事务的类)将仅在实例化对象时使用guice注入事务,并保留现有的应用程序代码,在必要时更新事务。例如,此提供程序可用于向当前事务实例注入新对象:

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

    是否有其他方法更新现有类使用的事务实例,而不必一次迁移每个类?

    2 回复  |  直到 16 年前
        1
  •  6
  •   Fernando    16 年前

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

    1. 在guice-ified类上使用正确的事务实例
    2. 在遗留类上使用正确的事务实例。

    对于“1”,您的自定义提供程序可以工作,但我将为事务创建自定义范围,并在该范围绑定事务类。见 http://code.google.com/p/google-guice/wiki/CustomScopes 有关自定义范围的说明。

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

        2
  •  1
  •   Jesse Wilson    16 年前

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

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

    …然后使用 FactoryProvider 绑定工厂:

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

    然后你可以注射 DataAccessClassFactory 无论您需要在哪里构建 DataAccessClass . 尽管需要单独的.jar文件,但assistedinject包含在guice 2中。