如何在不修改 DAO class 的情况下指定要使用的实体管理器工厂?
How can I specify which entity manager factory to use, without modifying the DAO class?
我有一个 Java 7 / Spring 3.2.17 应用程序,它必须连接到两个不同的数据库,所以我有两个不同的 persistence.xml 文件,每个文件都声明自己持久化单元。
在我的应用程序上下文中,我定义了两个实体管理器工厂,例如:
<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDatasource1" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence1.xml" />
<property name="persistenceUnitName" value="pu1" />
...
</bean>
在我的 DAO classes 中,我只是让 Spring 注入实体管理器:
@PersistenceContext
private EntityManager entityManager;
public void setEntityManager (...) { ... }
Spring 抱怨我有两个 EM 工厂,所以它不知道该使用哪个:
NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: emf1,emf2
我已经通过部分解决了,像这样:
@PersistenceContext(unitName = "pu1")
private EntityManager entityManager;
public void setEntityManager (...) { ... }
这解决了 classes 连接到第一个数据库的问题。我的问题是其他数据库的 classes 是第三方库的一部分,因此我无法修改它们以添加 unitName
属性。 还有其他方法吗?
我尝试了几个选项,但所有选项都会导致相同的错误消息:
- 扩展 class 这样我就可以 "override the annotation":
public class MyDao extends TheDaoThatICannotModify {
@Override
@PersistenceContext(unitName = "pu2")
public void setEntityManager (EntityManager em) {
super.setEntityManager(em);
}
}
- 自己实例化 EM 并注入:
<bean id="entityManager2" factory-bean="emf2" factory-method="getObject" />
<bean id="myDao" class="com.foo.TheDaoThatICannotModify">
<property name="entityManager" ref="entityManager2" />
</bean>
将 primary="true"
属性添加到我的 emf2
bean(并将 primary="false"
添加到 emf1
)。
将 autowire-candidate="false"
属性添加到我的 emf1
bean。
我让它工作了......通过使用 Spring 注入只用我自己的 类,并将 EM 传递给 evil DAOs 我自己:
public class MyDaoSingletonFactoryIsh {
@PersistenceContext(unitName = "pu2")
private EntityManager em; // Injected by Spring
private static TheDaoThatICannotModify dao = null;
public TheDaoThatICannotModify getDAO() {
if (dao == null) {
dao = new TheDaoThatICannotModify();
dao.setEntityManager(em);
}
return dao;
}
}
我不知道如何调用这种模式:工厂、单例、包装器?它实际上不属于这些类别中的任何一个,它是它们的奇怪组合。这可能不是一个好兆头,它看起来像一个巨大的代码味道,我宁愿避免它。但至少它是有效的,所以,缺乏更好的解决方案...
我有一个 Java 7 / Spring 3.2.17 应用程序,它必须连接到两个不同的数据库,所以我有两个不同的 persistence.xml 文件,每个文件都声明自己持久化单元。
在我的应用程序上下文中,我定义了两个实体管理器工厂,例如:
<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDatasource1" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence1.xml" />
<property name="persistenceUnitName" value="pu1" />
...
</bean>
在我的 DAO classes 中,我只是让 Spring 注入实体管理器:
@PersistenceContext
private EntityManager entityManager;
public void setEntityManager (...) { ... }
Spring 抱怨我有两个 EM 工厂,所以它不知道该使用哪个:
NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: emf1,emf2
我已经通过
@PersistenceContext(unitName = "pu1")
private EntityManager entityManager;
public void setEntityManager (...) { ... }
这解决了 classes 连接到第一个数据库的问题。我的问题是其他数据库的 classes 是第三方库的一部分,因此我无法修改它们以添加 unitName
属性。 还有其他方法吗?
我尝试了几个选项,但所有选项都会导致相同的错误消息:
- 扩展 class 这样我就可以 "override the annotation":
public class MyDao extends TheDaoThatICannotModify {
@Override
@PersistenceContext(unitName = "pu2")
public void setEntityManager (EntityManager em) {
super.setEntityManager(em);
}
}
- 自己实例化 EM 并注入:
<bean id="entityManager2" factory-bean="emf2" factory-method="getObject" />
<bean id="myDao" class="com.foo.TheDaoThatICannotModify">
<property name="entityManager" ref="entityManager2" />
</bean>
将
primary="true"
属性添加到我的emf2
bean(并将primary="false"
添加到emf1
)。将
autowire-candidate="false"
属性添加到我的emf1
bean。
我让它工作了......通过使用 Spring 注入只用我自己的 类,并将 EM 传递给 evil DAOs 我自己:
public class MyDaoSingletonFactoryIsh {
@PersistenceContext(unitName = "pu2")
private EntityManager em; // Injected by Spring
private static TheDaoThatICannotModify dao = null;
public TheDaoThatICannotModify getDAO() {
if (dao == null) {
dao = new TheDaoThatICannotModify();
dao.setEntityManager(em);
}
return dao;
}
}
我不知道如何调用这种模式:工厂、单例、包装器?它实际上不属于这些类别中的任何一个,它是它们的奇怪组合。这可能不是一个好兆头,它看起来像一个巨大的代码味道,我宁愿避免它。但至少它是有效的,所以,缺乏更好的解决方案...