如何让容器管理事务 (CMT) 与 EJB 3.1、Hibernate 3.6、JPA 2.0、JBoss 和 MySQL 配合使用
我试图让 CMT 与 JPA EntityManager 和 EJB 一起使用,但出现了以下错误。 (堆栈 trance 被截断):
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 创建为接口类型。
EJB 是否需要在 web.xml 中定义或映射?
假设 web.xml 中需要引用,我已将 EJB 引用添加到 web.xml(见下文),但现在我收到一个新错误(见下文)
添加到 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。
EAR 中 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>
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)创建一个设置豆子:
@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;
}
I was trying to get CMT working with JPA EntityManagers and EJBs, but came up with the error below. (stack trance truncated):
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}
My classes:
Servlet that access the Session Bean:
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 interface:
@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);
}
Stateless Session Bean definition:
@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;
}
}
file 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>
When it says "cannot resolve reference", where else can I define the beans? ejb-jar.xml isn't needed with EJB3. Is there some other config file that I'm missing?
UPDATE:
I have updated the code segments above so that the bean is created as the interface type instead, as per the answer below.
Do the EJBs need to be defined or mapped in web.xml?
Assuming that a reference is required in web.xml, I have added an EJB ref to web.xml (see below), but now I'm receiving a new error (see below)
lines added to 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>
new error message now being received:
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
Update:
"Local" interface works just fine (i.e. doesn't have to be Remote)
I got it to work by deploying within an Enterprise Application Project within Eclipse. No references to beans are required within web.xml, ejb-jar.xml, or application.xml.
Contents of application.xml within EAR being deployed to 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>
SessionBean class:
@Stateless
@Local(SessionBeanLocal.class)
public class SessionBean implements SessionBeanLocal {
@PersistenceContext(unitName="JPAtestProjectPersistenceUnit")
private EntityManager em;
Interface class:
@Local
public interface SessionBeanLocal {
TestTiger addTestTiger(String testTigerName);
MOST IMPORTANT change that got things working: inside the class that holds the session been local variable, a setting was required for the container (JBoss AS) to create the 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要注入远程接口而不是 Bean
You need to inject the remote interface and not the Bean
不要注入静态字段,注入是实例成员,在创建对象时发生,而静态字段是类成员。这很可能是异常的原因。
Don't do injections into static field, injections are instance members and happen when object is created, whereas static field is a class member. This is most probably the cause for exception.
我已经获得了一个可行的解决方案:
@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:
本地接口类:
SessionBean 类:
使事情正常运行的最重要的更改:在保存会话的类内部是可变的(例如在 Struts 操作 servlet 中,但可以是任何 servlet) ,容器(JBoss AS)需要一个setter方法来创建bean:
文件persistnce.xml:
mysql-dx.xml(在目录 jboss-server-dir/server/default/deploy 中):
注意:如果“持久性类管理”,则不需要在 persistence.xml 中定义类(通过“”)在 Eclipse JPA 项目(即包含 JPA 2.0 实体类和 persistence.xml 的项目)的“Java Persistence”项目属性面板中设置为“自动发现带注释的类”
注意:此解决方案基于: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 与 EntityManager)。请随意对我的解决方案的这一部分发表更多评论,因为我仍然在思考它!将要
I have obtained a working solution:
@Local interface works just fine (i.e. doesn't have to be Remote)
No references to beans are required within web.xml, ejb-jar.xml, application.xml, or any jboss config file.
I got it to work by deploying within an "Enterprise Application Project" (EAP) within Eclipse. This project contains "Deployment Assembly" that contains the .jar containing JPA Entity Classes, and another .jar that contains other business-logic classes. The EAP has those two projects PLUS the EJB project and the "Dynamic Web Project" (creates a .war) for a total of 4 projects on it's build path. Jboss AS tool within Eclipse publishes/deploys the EAP to the Jboss server. Contents of application.xml within EAP being deployed to Jboss:
Local Interface class:
SessionBean class:
MOST IMPORTANT change that got things working: inside the class that holds the session been variable (e.g. inside a Struts action servlet, but could be any servlet), a setter method was required for the container (JBoss AS) to create the bean:
file persistnce.xml:
mysql-dx.xml (in directory jboss-server-dir/server/default/deploy):
NOTE: Classes do not need to be defined in persistence.xml (via "< class >") if "Persistence Class Management" is set to "Discover annotated classes automatically" in "Java Persistence" project property panel for the Eclipse JPA project (i.e. the project that containers your JPA 2.0 Entity classes and persistence.xml)
NOTE: This solution is based on: EJB3.1, Eclipse Helios SR2, Hibernate 3.6, JPA 2.0, JBoss 6, MySQL 5.5.10
NOTE: Regarding "Container Managed Transactions" (CMT). The Hibernate manual references them, and indicates that you need to set persistence.xml properties such as "hibernate.transaction.factory_class" to value of: "org.hibernate.transaction.CMTTransactionFactory". This is not the case if you are using JPA EntityManager instead of native hibernate. I didn't required any such custom CMT properties in persistence.xml. This is where Hibernate gets confusing, between the two ways to implement it (i.e. SessionFactory vs EntityManager). Please feel free to comment more on this part of my solution as I'm still just wrapping my head around it! Will