5

我在 tomcat 7 上使用 Hibernate 和 Weld CDI 运行一个项目。我编写了一个 ServletContextListener 来在应用程序启动期间创建 EntityManagerFactory 和 EntityManager。

public class PersistenceListener implements ServletContextListener {

     private static EntityManagerFactory entityManagerFactory;

     public void contextInitialized(ServletContextEvent sce){
     ServletContext context = sce.getServletContext();
     entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
     }

     public void contextDestroyed(ServletContextEvent sce) {
     entityManagerFactory.close();
     }


     public static EntityManager createEntityManager() {
            if (entityManagerFactory == null) {
                throw new IllegalStateException("Context is not initialized yet.");
            }

            return entityManagerFactory.createEntityManager();
        }

}

我可以在我的测试类中使用我的 entityManager(它是一个 arquillian 测试类),只需通过以下代码创建它

EntityManager em = PersistenceListener.createEntityManager();
               em.getTransaction().begin();
                   em.createQuery("delete from Game").executeUpdate();
                   em.getTransaction().commit();

这是我的测试类的完整代码

    @RunWith(Arquillian.class)
    public class HibernateTestSample {

           @Deployment
           public static WebArchive createTestArchive()
           {
               MavenDependencyResolver resolver = DependencyResolvers.use(
                        MavenDependencyResolver.class).loadMetadataFromPom("pom.xml");

               WebArchive webArchive=  ShrinkWrap
                    .create(WebArchive.class, "ROOT.war")
                    .addClasses(CdiTestBean.class,HibernateListener.class,PersistenceListener.class)
                    .addAsLibraries(
                                resolver.artifact("org.jboss.weld.servlet:weld-servlet")
//                              .artifact("org.hibernate.javax.persistence:hibernate-jpa-2.0-api")
                                .artifact("org.apache.tomcat:tomcat-dbcp")
                                .artifact("org.hibernate:hibernate-entitymanager")
                                .artifact("org.hibernate:hibernate-validator")
                                .artifact("org.hibernate:hibernate-core")   
                                .artifact("com.h2database:h2")
                                .artifact("mysql:mysql-connector-java")
                                .resolveAs(GenericArchive.class))

                    .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
                    .addAsWebInfResource("test-persistence.xml", "classes/META-INF/persistence.xml")
                    .addAsWebInfResource("hibernate.cfg.xml", "classes/hibernate.cfg.xml") 
//                  .addAsWebInfResource("context.xml", "classes/META-INF/context.xml")
                    .addAsManifestResource("context.xml", "context.xml")
                    .setWebXML("hibernate-web.xml");
              System.out.println(webArchive.toString(true));

              return webArchive;
           }


           @Test
           public void myTest()
                   throws Exception {                                                      

               EntityManager em = PersistenceListener.createEntityManager();
               em.getTransaction().begin();
                       em.createQuery("delete from Game").executeUpdate();
                   em.getTransaction().commit();
                  ...............
                      .......
                      ...


           }
    }

但我想将我的 entityManager 注入我的班级。我在另一篇文章中读到 我不能在课堂上使用@PersistenceContext,因此我决定使用生产者来注入我的实体管理器。但这对我不起作用,请告诉我我在这里做错了什么(我是 CDI 的新手)

这是我的新 ServletContextListener

public class PersistenceListener implements ServletContextListener {

     private static EntityManagerFactory entityManagerFactory;

     @Produces
     private EntityManager entityManager;

     public void contextInitialized(ServletContextEvent sce){
     ServletContext context = sce.getServletContext();
     entityManagerFactory = Persistence.createEntityManagerFactory("hibernate-test");
     createEntityManager();
     }

     public void contextDestroyed(ServletContextEvent sce) {
     entityManagerFactory.close();
     }


     public void createEntityManager() {
            if (entityManagerFactory == null) {
                throw new IllegalStateException("Context is not initialized yet.");
            }

            this.entityManager =  entityManagerFactory.createEntityManager();
        }

我正在注入我的测试类

@Inject
private EntityManager em;

它是空的

4

2 回答 2

3

通过实现 ServletContextListener 通过 Servlet 规范创建的实例与 CDI 稍后将创建以解析您的@Produces字段的实例不同。

此外,我推荐这篇关于 EntityManager 的信息丰富的博客文章:http: //struberg.wordpress.com/2012/04/25/is-there-a-way-to-fix-the-jpa-entitymanager/

不过它可能有点过时了,因为如果我没记错的话,我已经在 deltaspike 的作品中看到了@TransactionScoped。

最后,您可能已经想到,现在拥有一个单例 EntityManager 并不是您想要的,但为了完整起见,您的 ContextListener 和 CDI 之间的协同缺失可以通过使用 Deltaspike 的 CdiCtrl 和 Deltspike Core 的 BeanProvider 来解决。

如何将 CDI ApplicationScope 附加到您当前的线程http://struberg.wordpress.com/2012/03/17/controlling-cdi-containers-in-se-and-ee/

然后你可以拾取一个带有注释的 bean@ApplicationScoped并设置它。拾取通过MyBean myBean = BeanProvider.getContextualReference(MyBean.class, false); http://deltaspike.apache.org/deltaspike/core.html完成

希望 CDI 1.1 能让这更流畅一点

更新:关于 D​​eltaspike 列表的讨论是在大约一个月内让 0.5 成为一个较小的版本。希望新的 Servlet 模块能很好地解决这个问题。

https://issues.apache.org/jira/browse/DELTASPIKE-376 https://issues.apache.org/jira/browse/DELTASPIKE-377

于 2013-05-31T12:18:03.003 回答
1

你需要@Produces你的createEntityManager方法,而不是领域。

于 2013-05-30T16:27:33.807 回答