如何在不修改 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 属性。 还有其他方法吗?


我尝试了几个选项,但所有选项都会导致相同的错误消息:

  1. 扩展 class 这样我就可以 "override the annotation":
public class MyDao extends TheDaoThatICannotModify {
    @Override
    @PersistenceContext(unitName = "pu2")
    public void setEntityManager (EntityManager em) {
        super.setEntityManager(em);
    }
}
  1. 自己实例化 EM 并注入:
<bean id="entityManager2" factory-bean="emf2" factory-method="getObject" />

<bean id="myDao" class="com.foo.TheDaoThatICannotModify">
    <property name="entityManager" ref="entityManager2" />
</bean>
  1. primary="true" 属性添加到我的 emf2 bean(并将 primary="false" 添加到 emf1)。

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

我不知道如何调用这种模式:工厂、单例、包装器?它实际上不属于这些类别中的任何一个,它是它们的奇怪组合。这可能不是一个好兆头,它看起来像一个巨大的代码味道,我宁愿避免它。但至少它是有效的,所以,缺乏更好的解决方案...