有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

需要java模式建议(Hibernate+Guice)

我正在寻找关于如何将运行时依赖项注入从Hibernate检索到的JPA实体的建议。我的问题主要是:

我有许多不同的事务对象子类。每个事务子类在执行时都有不同的行为,并且需要一组不同于环境的依赖项。这些事务对象由Hibernate作为JPA实体进行管理,因此我无法像在应用程序的其余部分中那样,有效地使用Guice进行依赖项注入来填充实例的环境依赖项

为了解决这个问题,我采取了一种类似于访问者模式的方法,如下所示:

public abstract class Transaction {
    // ...snip...
    public abstract void apply(Transactor transactor);
}

public class TransactionA extends Transaction {
    public void apply(Transactor transactor) {
        transactor.execute(this);
    }
}

public class TransactionB extends Transaction {
    public void apply(Transactor transactor) {
        transactor.execute(this);
    }
}
// other Transaction subclasses with the same boilerplate

public interface Transactor {
    public void execute(TransactionA trans);
    public void execute(TransactionB trans);
    // corresponding methods for other transaction types.
}

public class BeginTransactor {
     @Inject
     private Foo execAdep;
     public void execute(TransactionA trans) {
         execAdep.doSomething(...)    
     }

     @Inject
     private Bar execBdep;
     public void execute(TransactionB trans) {
         execBdep.doOther(...)    
     }
 }

对于事务生命周期的不同部分,我有不同的Transactior实现。可以使用Guice将这些依赖注入到我想要处理事务的上下文中,我只需调用:

 Transactor transactor = injector.getInstance(BeginTransactor.class); //Guice injection
 Transaction t = ... //get a transaction instance
 t.apply(transactor);

我不喜欢这种方法的地方在于:(1)并非每种类型的事务都应该在每个生命周期阶段都是可执行的,但每个事务处理者必须为每个事务子类实现execute()方法;(2)本质上,注入的依赖项都不用于处理多个事务类型

本质上,我的事务处理接口&;实现中有许多不相关的crud聚集在一起。理想情况下,我只需要对事务对象本身使用execute()方法,但我不希望调用代码必须知道事务的类型或它所需要的依赖项。此外,这可能会使测试更加困难,因为如果execute()方法是事务对象上的一个具体方法,我无法轻松模拟它。使用Transactior接口意味着我可以根据需要轻松模拟它

有谁能建议如何以一种类型安全的方式解决这个问题,这种方式不会导致在事务处理程序中聚集一堆几乎不相关的行为,而是保持可测试性并允许依赖项注入


共 (2) 个答案

  1. # 1 楼答案

    检查:http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Interceptor.html

    将hibernate配置为使用Intercetor。方法

    public Object instantiate(String entityName,
                          EntityMode entityMode,
                          Serializable id)
    

    将被要求

    Instantiate the entity class. Return null to indicate that Hibernate
    should use the default constructor of the class. The identifier property
    of the returned instance should be initialized with the given identifier. 
    

    你可以打电话给你的注射器。从那里获取实例()

    也许,可以使用getEntity()或onLoad()方法。通过onLoad()方法,可以调用注入器。injectMembers()

  2. # 2 楼答案

    我使用guice进行交易,但我使用AOP来执行它们。我几乎没有样板,这是以牺牲一点“魔力”为代价的。只要你的截获类是“在俱乐部”,它的工作非常好

    class BusinessLogic {
        @Inject public EntityManager em;
    
        @Transactional
        publc void doSomething() {
           //...
           em.persist(myObj);
        }
    
        @Transactional
        public void doSomethingElse() {
           //...
           em.delete(myObj);
        }
    }
    
    class TransactionalInterceptor implements MethodInterceptor {
        @Inject static Injector injector;
        public Object intercept(MethodInvocation invocation) {
            EntityManager em = injector.getInstance(EntityManager.class);
            em.getTransaction().begin();
            Object result = invocation.proceed();
            em.getTransaction().commit();
            return result;
        }
    }
    class TransactionalModule extends AbstractModule {
        public void configure() {
            requestStaticInjection(TransactionalInterceptor.class);
            bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class),
                     new TransactionalInterceptor());
        }
    }