如何检索 Spring 的实体管理器工厂?

How to retrieve Spring's entity manager factory?

我正在尝试

在我的应用程序上下文 XML 文件中,我有这个 bean:

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
      id="entityManagerFactory"> ... </bean>

在我的 DAO 中,我只是为实体管理器注释 setter 并且 Spring 完成了所有的魔法:

@PersistenceContext
public void setEntityManager(EntityManager em) {
    this.em = em;
}

在 Spring 2.5+ 中,我只用 @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {"/applicationContext-test.xml"}) 注释我的测试 class。但是我的Spring版本太旧了,没有SpringJUnit4ClassRunner。因此,我的 JUnit 测试没有 Spring 魔法。相反,我自己做这一切:

// Load the XML file myself
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocations(new String[] { "classpath:applicationContext-test.xml" });
appContext.refresh();

// Retrieve the entity manager factory
Object obj = appContext.getBean("entityManagerFactory");
// ***** The following line throws an exception: *****
LocalContainerEntityManagerFactoryBean aux = (LocalContainerEntityManagerFactoryBean) obj;
EntityManagerFactory emf = aux.getObject();

// Instantiate the EM and inject it into the DAOs
EntityManager em = emf.createEntityManager();
myDAO.setEntityManager(em);

当我尝试将 obj 转换为 aux 时,出现 ClassCastException: Cannot cast $Proxy23 ... 异常。但是,如果我在 Eclipse 中设置断点并检查 obj,它实际上 LocalContainerEntityManagerFactoryBean 的一个实例。

我已经尝试过 this approach 我已经在很多问题中看到了这里的问题。但是,AopUtils.isJdkDynamicProxy(obj) returns 错误。此外,即使尝试转换 (Advised) obj 也会引发相同的异常。

我也试过将 obj 转换为 FactoryBean, which is one of the interfaces implemented by LocalContainerEntityManagerFactoryBean... 是的,它抛出了同样的异常。这令人困惑,因为几乎每个 "class cast exception proxy" 的答案都说 "you can only cast to interfaces, not to classes".

所以,我的问题是:

emf = Persistence.createEntityManagerFactory("myPersistenceUnit");
em = emf.createEntityManager();

工作正常,但我丢失了 applicationContext-test.xml 文件中定义的 <aop:config><tx:advice> 条目。

您可以使用另一个版本的 getBean(...) 方法来更严格地定义所需的类型,请参阅 official Spring 2.0 JavaDoc:

public Object getBean(String name, Class requiredType)

其中指出:

requiredType - type the bean must match. Can be an interface or superclass of the actual class, or null for any match. For example, if the value is Object.class, this method will succeed whatever the class of the returned instance.

因此,要解决你的强制转换问题,你需要这样实现:

// Retrieve the entity manager factory
EntityManagerFactory emf = (EntityManagerFactory) 
   appContext.getBean("entityManagerFactory", javax.persistence.EntityManagerFactory.class);

有了这个,你将直接检索到一个"neutral" EMF,与JPA规范描述的接口兼容。在运行时,这将是一个代理对象,但您可以按照最初预期的方式使用它:

// Instantiate the EM and inject it into the DAOs
EntityManager em = emf.createEntityManager();
// ... whatever comes here - most likely: doing some CRUD operations...

希望对您有所帮助。