我正在尝试手动连接Spring Data JPA对象,以便生成DAO代理(也称为Repositories)-而不使用Spring bean容器。
不可避免地,我会被问及为什么要这样做:因为我们的项目已经在使用Google Guice(并且在UI上使用Gin和GWT),我们不想维护另一个IoC容器配置,或者拉入所有相关的依赖项。我知道我们可能可以使用Guice的 SpringIntegration ,但这将是最后的办法。
似乎一切都可以手动连接起来,但由于没有很好的文档,我非常困难。
根据Spring Data用户指南,可以独立使用repository factories standalone。不幸的是,示例显示了一个抽象类RepositoryFactorySupport
。经过一些搜索,我成功找到了JpaRepositoryFactory
JpaRepositoryFactory
实际上运作得相当不错,但它不会自动创建事务。必须手动管理事务,否则将不会将任何内容持久化到数据库中:
entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();
问题在于 @Transactional
注释不会自动使用,需要 TransactionInterceptor
的帮助。
值得庆幸的是,JpaRepositoryFactory
可以接受回调函数,在返回生成的 Repository 代理之前添加更多的 AOP 建议:
final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(emf.createEntityManager());
factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
@Override
public void postProcess(ProxyFactory factory) {
factory.addAdvice(new TransactionInterceptor(xactManager, new AnnotationTransactionAttributeSource()));
}
});
事情不是很顺利。在代码调试器中,TransactionInterceptor
确实创建了一个事务 - 但是它关联的是错误的 EntityManager
。Spring 通过查看当前执行线程来管理活动的 EntityManager
。 TransactionInterceptor
这样做,并发现线程上没有绑定到活动的 EntityManager
,因此决定创建一个新的。
然而,这个新的 EntityManager
不是传递给 JpaRepositoryFactory
构造函数并且被创建的实例,构造函数需要一个 EntityManager
。问题是,如何使 TransactionInterceptor
和 JpaRepositoryFactory
使用相同的 EntityManager
?
更新:
在撰写本文时,我找到了解决问题的方法,但仍然可能不是最理想的解决方案。我将把这个解决方案作为单独的答案发表。如果有更好的使用 Spring Data JPA 的方式,请告诉我。