Spring 2.0.7获取EntityManagerFactory遇类转换异常,求JUnit测试方案
你的问题核心是没搞清楚Spring对FactoryBean的处理逻辑——默认调用getBean("beanId")时,Spring返回的是FactoryBean生产的对象(也就是EntityManagerFactory),而不是FactoryBean本身(LocalContainerEntityManagerFactoryBean),所以你拿到的其实是被Spring代理后的EntityManagerFactory实例,自然无法强转为LocalContainerEntityManagerFactoryBean。
下面给你两种可行的修复方案,都不用升级Spring:
方案1:直接获取代理后的EntityManagerFactory
这是最简单的方式,直接把getBean的结果强转为EntityManagerFactory即可,这个实例已经包含了你XML配置中的<aop:config>和<tx:advice>增强,完全符合你的需求:
// 手动加载XML文件 XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocations(new String[] { "classpath:applicationContext-test.xml" }); appContext.refresh(); // 直接获取EntityManagerFactory代理实例 EntityManagerFactory emf = (EntityManagerFactory) appContext.getBean("entityManagerFactory"); // 实例化EM并注入DAO EntityManager em = emf.createEntityManager(); myDAO.setEntityManager(em);
方案2:获取FactoryBean本身(带&前缀)
如果你确实需要拿到LocalContainerEntityManagerFactoryBean实例,Spring提供了特殊的语法:在bean ID前加&前缀,这样就能获取FactoryBean本身而不是它生产的对象:
// 手动加载XML文件 XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocations(new String[] { "classpath:applicationContext-test.xml" }); appContext.refresh(); // 注意bean名称前的&,获取FactoryBean本身 LocalContainerEntityManagerFactoryBean aux = (LocalContainerEntityManagerFactoryBean) appContext.getBean("&entityManagerFactory"); EntityManagerFactory emf = aux.getObject(); // 实例化EM并注入DAO EntityManager em = emf.createEntityManager(); myDAO.setEntityManager(em);
补充说明
你提到调试时看到obj是LocalContainerEntityManagerFactoryBean实例,这是因为调试工具通常会显示代理的目标对象,但运行时实际对象是Spring生成的代理类(可能是CGLIB代理,所以AopUtils.isJdkDynamicProxy(obj)返回false),导致强转失败。
另外,不要用Persistence.createEntityManagerFactory,因为它会绕过Spring的上下文管理,确实会丢失AOP和事务配置,而上面两种方案都是基于Spring上下文的,完全保留了你的配置。
内容的提问来源于stack exchange,提问作者AJPerez

