在tomcat中使用生产者注入EntityManager

时间:2013-05-30 13:49:41

标签: hibernate tomcat cdi jboss-weld jboss-arquillian

我在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注入我的班级。我读in an other post我不能在课堂上使用@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;

它为空

2 个答案:

答案 0 :(得分: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并不是你想要的,但为了完整起见,使用Deltaspike的CdiCtrl和Deltspike Core的BeanProvider可以在一定程度上修复ContextListener和CDI之间的协同作用。

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

然后你可以拾取一个用@ApplicationScoped注释的bean并进行设置。取件由MyBean myBean = BeanProvider.getContextualReference(MyBean.class, false); http://deltaspike.apache.org/deltaspike/core.html

完成

希望CDI 1.1能让它更流畅

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

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

答案 1 :(得分:1)

您的@Produces方法需要createEntityManager,而不是字段。