如何使用EJB 3.1,Hibernate 3.6,JPA 2.0,JBoss和MySQL进行容器管理事务(CMT)

时间:2011-03-22 05:00:07

标签: jpa jboss ejb code-injection entitymanager

我试图让CMT使用JPA EntityManagers和EJB,但是我想出了下面的错误。 (堆栈恍惚截断):

Caused by: java.lang.RuntimeException: **Could not resolve @EJB reference: [EJB Reference: beanInterface 'com.mydomain.beans.TestBean2', beanName 'testBean2', mappedName 'null', lookupName 'null',** owning unit 'AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}']
for environment entry: env/com.mydomain.action.SearchAction/testBean in unit AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}

我的课程:

访问会话Bean的Servlet:

public class SearchActionExample extends Action {
    @EJB
    private static TestBeanServiceInterface testBean;

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        testBean.addSource("TEST SOURCE NAME", 88, 99);
        Service service = testBean.findService("HBA", "MEL");

        return mapping.findForward("success");
    }
}

远程接口:

@Remote
public interface TestBeanServiceInterface {
    // Source is my own custom entity
    void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients);

    // Service is my own Custom entity    
    Service findService(String departureAirportCode, String arrivalAirportCode);
}

无状态会话Bean定义:

@Stateless
public class TestBeanService implements TestBeanServiceInterface {

    @PersistenceContext(unitName="mydomainJPA")
    private EntityManager em;

    public void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients) {
        Source source = new Source();
        source.setName(sourceName);
        source.setNewThreadSleepTime(newthreadsleeptime);
        source.setMaxActiveHttpClients(maxactivehttpclients);
        em.persist(source);
    }
    public Service findService(String departureAirportCode, String arrivalAirportCode) {
        String queryString = "from Service where departureairportcode = '" + departureAirportCode + "' and arrivalairportcode = '" + arrivalAirportCode + "'";
        Service service = (Service)em.createQuery(queryString).getSingleResult();
        return service;
    }
}

文件persistnce.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="mydomainJPA" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <class>com.mydomain.entities.Service</class>
<class>com.mydomain.entities.Source</class>
    <properties>
        <property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
        <property name="hibernate.current_session_context_class" value="jta"/>   
    </properties>   
</persistence-unit>

当它说“无法解析引用”时,我还能在哪里定义bean? EJB3不需要ejb-jar.xml。是否有一些我缺少的其他配置文件?


更新

  • 我已经更新了上面的代码段,以便根据以下答案创建bean作为接口类型。

  • 是否需要在web.xml中定义或映射EJB?

  • 假设web.xml中需要引用,我在web.xml中添加了一个EJB引用(见下文),但现在我收到一个新错误(见下文)

    < / LI>

添加到web.xml的行:

<ejb-ref>
    <ejb-ref-name>ejb/TestBeanEJBname</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>com.mydomain.action.TestBeanService</home>
    <remote>com.mydomain.action.TestBeanServiceInterface</remote>
 </ejb-ref>

现在收到新的错误消息:

12:11:00,980 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to PostClassLoader: name=vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/purejetWeb.war state=ClassLoader mode=Manual requiredState=PostClassLoader: org.jboss.deployers.spi.DeploymentException: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: au.com.purejet.action.TestBeanServiceInterface

Caused by: java.lang.IllegalStateException: Failed to find ContainerDependencyMetaData for interface: com.mydomain.action.TestBeanServiceInterface
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbInterface(MappedReferenceMetaDataResolverDeployer.java:1255) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolveEjbRefs(MappedReferenceMetaDataResolverDeployer.java:1099) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.resolve(MappedReferenceMetaDataResolverDeployer.java:807) [:6.0.0.Final]
at org.jboss.deployment.MappedReferenceMetaDataResolverDeployer.internalDeploy(MappedReferenceMetaDataResolverDeployer.java:181) [:6.0.0.Final]
... 39 more

更新

“本地”界面工作正常(即不必是远程)

我通过在Eclipse中的企业应用程序项目中部署来实现它。在web.xml,ejb-jar.xml或application.xml中不需要引用bean。

部署到Jboss的EAR中的application.xml的内容:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>myprojects</display-name>
<module>
<web>
<web-uri>myproject.war</web-uri>
<context-root>myproject</context-root>
</web>
</module>
<module>
<ejb>myprojectsEJB.jar</ejb>
</module>
</application>

SessionBean类:

@Stateless
@Local(SessionBeanLocal.class)

public class SessionBean implements SessionBeanLocal {

@PersistenceContext(unitName="JPAtestProjectPersistenceUnit")
private EntityManager em;

接口类:

@Local
public interface SessionBeanLocal {

TestTiger addTestTiger(String testTigerName);

最重要的改变让事情变得有效:在持有会话的类中是局部变量,容器(JBoss AS)需要一个设置来创建bean:

@EJB()
private TestBean3Local beanVariable;

public void setBeanVariable(TestBean3Local beanVariable) {
    System.out.println("=====\n\nSET BEAN VARIABE SETTER WAS CALLED. (BY CONTAINER?)  \n\n=======");
    this.beanVariable = beanVariable;
}

3 个答案:

答案 0 :(得分:1)

您需要注入远程接口而不是Bean

public class SearchActionExample extends Action {
    @EJB
    private static TestBean2Remote testBean;

答案 1 :(得分:0)

public class SearchActionExample extends Action {
    @EJB
    private static TestBeanServiceInterface testBean;

不要在静态字段中进行注入,注入是实例成员,并且在创建对象时发生,而静态字段是成员。这很可能是异常的原因。

答案 2 :(得分:0)

我已经获得了一个有效的解决方案:

@Local界面工作正常(即不必是远程)

web.xml,ejb-jar.xml,application.xml或任何jboss配置文件中不需要对bean的引用。

我通过在Eclipse中的“企业应用程序项目”(EAP)中部署来实现它。此项目包含“部署程序集”,其中包含包含JPA实体类的.jar,以及包含其他业务逻辑类的另一个.jar。 EAP将这两个项目放在EJB项目和“动态Web项目”(创建.war)上,在其构建路径上共有4个项目。 Eclipse中的Jboss AS工具将EAP发布/部署到Jboss服务器。 EAP中的application.xml内容部署到Jboss:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
    <display-name>myprojects</display-name>
    <module>
        <web>
            <web-uri>myproject.war</web-uri>
            <context-root>myproject</context-root>
        </web>
    </module>
    <module>
        <ejb>myprojectsEJB.jar</ejb>
    </module>
</application>

本地接口类:

package com.myproject.beans;
import javax.ejb.Local;

import com.myproject.entities.Lion;

@Local
public interface SessionBeanLocal {
Lion addLion(String lionName);
}

SessionBean类:

package com.myproject.beans;

import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.myproject.Lion;

@Stateless
@Local(SessionBeanLocal.class)
public class SessionBean implements SessionBeanLocal {

@PersistenceContext(unitName="PersistenceUnitNameInPersistenceXML")
private EntityManager em;

public Lion addLion(String lionName) {
    Lion lion = new Lion(lionName);
    em.persist(lion);
}

最重要的改变让事情变得有效:在持有会话的类内部是可变的(例如在Struts动作servlet中,但可能是任何servlet),容器(JBoss AS)需要一个setter方法来创建豆:

@EJB()
private SessionBeanLocal bean;

public void setBean(SessionBeanLocal bean) {
    System.out.println("setBean setter was called by container (e.g. Jboss)");
    this.bean = bean;
}

public exampleStrutsServletMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
    PrintWriter out = response.getWriter();

    Lion lion = bean.addLion("Simba");  // this will persist the Lion within the persistence-context (and auto-generate an Id), and the container will manage when it's flushed to the database

    out.print("<html>LION ID = " + lion.getLionId() + "<html>");
}

文件persistnce.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="PersistenceUnitNameInPersistenceXML" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <properties>
    </properties>   
</persistence-unit>

mysql-dx.xml(在目录jboss-server-dir / server / default / deploy中):

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <local-tx-datasource>
        <jndi-name>MySqlDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/myProjectDatabase</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>username</user-name>
        <password>mypassword</password>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
        <metadata>
            <type-mapping>mySQL</type-mapping>
        </metadata>
    </local-tx-datasource>
</datasources>

注意:如果“持久性类管理”在“Java持久性”项目属性面板中设置为“自动发现带注释的类”,则不需要在persistence.xml中定义类(通过“&lt; class&gt;”) Eclipse JPA项目(即容纳JPA 2.0 Entity类和persistence.xml的项目)

注意:此解决方案基于:EJB3.1,Eclipse Helios SR2,Hibernate 3.6,JPA 2.0,JBoss 6,MySQL 5.5.10

注意:关于“容器管理交易”(CMT)。 Hibernate手册引用它们,并指示您需要将persistence.xml属性(例如“hibernate.transaction.factory_class”)设置为值:“org.hibernate.transaction.CMTTransactionFactory”。如果您使用JPA EntityManager而不是本机hibernate,则情况并非如此。我在persistence.xml中没有要求任何这样的自定义CMT属性。这是Hibernate在实现它的两种方式之间变得混乱的地方(即SessionFactory vs EntityManager)。请随时对我解决方案的这一部分发表更多评论,因为我仍然只是围绕着它!将