嵌入式JBoss EAP 6 / AS 7入门

时间:2013-02-22 20:00:55

标签: jboss7.x ejb-3.1 embedded-jboss jboss-eap-6

我正在尝试使用规范中描述的EJBContainer.createEJBContainer API嵌入JBoss(JSR 318:Enterprise JavaBeans,版本3.1,第22章:可嵌入使用),任何{ {3}}使用JBoss特定的API。

概述

  • 当我正常调用main方法时,会话bean调用成功。但似乎存在一些类加载问题,因为"java:jboss/UserTransaction"处的JNDI对象无法转换为javax.transaction.UserTransaction。
  • 所以我想这里需要various predecessors的类加载魔法。通过我的尝试,createEJBContainer找不到任何EJBContainerProviders并抛出EJBException。

请注意,并非所有问题都需要阅读所有后续细节。因此,如果这太难阅读,请查看问题部分。谢谢!

环境

JBoss AS 7.1.1.Final(jboss-as-7.1.1.Final.zip,只在standalone.xml中更改了日志记录配置)
(最初是JBoss EAP 6.0.1 GA,它是实际的目标环境 - 同样的问题)
Oracle JDK 1.7.0_11
Windows 7 Prof 64位

详细

无状态会话bean

package test.helloworld.impl;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import test.helloworld.api.HelloWorld;

@Stateless
@Remote(HelloWorld.class)
public class HelloWorldBean implements HelloWorld
{
    @Override
    public String salute()
    {
        return "Hello, world";
    }
}

...及其业务界面:

package test.helloworld.api;

public interface HelloWorld
{
    String salute();
}

客户端程序

package test.helloworld.client;

import static java.lang.System.out;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import javax.transaction.UserTransaction;
import test.helloworld.api.HelloWorld;


public class HelloWorldEmbeddedEjbTestClient
{
    public static void main(String[] args)
    {
        int status = 1;

        try
        {
            main();
            status = 0;
        }
        catch (Throwable e)
        {
            e.printStackTrace(System.err);
            System.err.flush();
        }
        finally
        {
            // Simply returning from main leaves some thread (and
            // hence the JVM) running for another 60s, so force exit
            System.exit(status);
        }
    }


    private static void main() throws Exception
    {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(EJBContainer.MODULES, new File[]{new File("./HelloWorld-EJB.jar")});
        EJBContainer container = EJBContainer.createEJBContainer(properties);

        try
        {
            Context jndiContext = container.getContext();
            Object serviceObj = jndiContext.lookup("java:global/HelloWorld-EJB/HelloWorldBean");
            out.println("service:\t" + serviceObj);
            HelloWorld service = (HelloWorld) serviceObj;
            out.println("result:\t" + service.salute());

            callInTx(service, jndiContext);
        }
        finally
        {
            out.println("closing EJBContainer...");
            container.close();
            out.println("EJBContainer closed.");
        }
    }


    private static void callInTx(HelloWorld service, Context jndiContext) throws Exception
    {
        UserTransaction tx = (UserTransaction) jndiContext.lookup("java:jboss/UserTransaction");
        tx.begin();
        out.println("result in tx:\t" + service.salute());
        tx.commit();
    }
}

包装

C:\蚀\项目\ HelloWorldSlSB客户端\ RT \的HelloWorld-api.jar文件:

META-INF/MANIFEST.MF
test/helloworld/api/HelloWorld.class

C:\蚀\项目\ HelloWorldSlSB客户端\ RT \的HelloWorld-EJB.jar:

META-INF/MANIFEST.MF
META-INF/jboss-deployment-structure.xml
test/helloworld/impl/HelloWorldBean.class
test/helloworld/api/HelloWorld.class

的HelloWorld-EJB.jar:META-INF / JBoss的部署-structure.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies></dependencies>
        <exclusions>
            <module name="Classpath"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

C:\蚀\项目\ HelloWorldSlSB客户端\室温\模块\测试\的HelloWorld \客户\主\ HelloWorldSlSB-client.jar中:

META-INF/MANIFEST.MF
test/helloworld/client/HelloWorldEmbeddedEjbTestClient.class

C:\蚀\项目\ HelloWorldSlSB客户端\室温\模块\测试\的HelloWorld \客户\主\ module.xml:          

    <main-class name="test.helloworld.client.HelloWorldEmbeddedEjbTestClient"/>

    <resources>
        <resource-root path="HelloWorldSlSB-Client.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.ejb.api"/>
        <module name="org.jboss.as.embedded" export="true"/>
<!--
        <module name="org.jboss.as.server" export="true"/>
-->
    </dependencies>
</module>

所有META-INF / MANIFEST.MF文件只包含“Manifest-Version:1.0”。

结果

直接调用

使用-Xmx512m -XX:MaxPermSize=256m直接调用HelloWorldEmbeddedEjbTestClient.main,类路径

C:\eclipse\output\HelloWorldSlSB-Client
C:\java\jboss-as-7\jboss-modules.jar
C:\java\jboss-as-7\modules\org\jboss\as\embedded\main\jboss-as-embedded-7.1.1.Final.jar
C:\java\jboss-as-7\modules\javax\ejb\api\main\jboss-ejb-api_3.1_spec-1.0.1.Final.jar
C:\java\jboss-as-7\modules\javax\transaction\api\main\jboss-transaction-api_1.1_spec-1.0.0.Final.jar
C:\java\jboss-as-7\modules\org\jboss\logging\main\jboss-logging-3.1.0.GA.jar
C:\java\jboss-as-7\modules\org\jboss\as\controller-client\main\jboss-as-controller-client-7.1.1.Final.jar
C:\java\jboss-as-7\modules\org\jboss\logmanager\main\jboss-logmanager-1.2.2.GA.jar
C:\java\jboss-as-7\modules\org\jboss\dmr\main\jboss-dmr-1.1.1.Final.jar
C:\eclipse\projects\HelloWorldSlSB-Client\rt\HelloWorld-API.jar

和系统属性

-Duser.language=en
-Djboss.home=c:/java/jboss-as-7
-Djboss.home.dir=c:/java/jboss-as-7
-Dorg.jboss.as.embedded.ejb3.BARREN=true
-Dfile.encoding=ISO-8859-1

EJB调用成功,但JNDI对象“java:jboss / UserTransaction”无法强制转换为javax.transaction.UserTransaction:

...
19:21:01,875 INFO  [org.jboss.ejb.client] (main) JBoss EJB Client version 1.0.5.Final
service:    Proxy for remote EJB StatelessEJBLocator{appName='', moduleName='HelloWorld-EJB', distinctName='', beanName='HelloWorldBean', view='interface test.helloworld.api.HelloWorld'}
result: Hello, world
closing EJBContainer...
19:21:06,362 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-7) JBAS015877: Stopped deployment HelloWorld-EJB.jar in 90ms
19:21:06,370 INFO  [org.jboss.as.repository] (pool-9-thread-1) JBAS014901: Content removed from location c:\java\jboss-as-7\standalone\data\content\35\424415b9a67d64fe8a6dc7ee0700480282f34b\content
19:21:06,370 INFO  [org.jboss.as.server] (pool-9-thread-1) JBAS018558: Undeployed "HelloWorld-EJB.jar"
19:21:06,390 INFO  [org.jboss.as.osgi] (MSC service thread 1-1) JBAS011942: Stopping OSGi Framework
EJBContainer closed.
java.lang.ClassCastException: org.jboss.tm.usertx.client.ServerVMClientUserTransaction cannot be cast to javax.transaction.UserTransaction
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.callInTx(HelloWorldEmbeddedEjbTestClient.java:65)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:52)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:21)

(看起来有点奇怪,因为在main的末尾会捕获并打印异常。但当然,它会在容器关闭之前发生。)

调试器显示JNDI对象的getClass()。getClassLoader()是org.jboss.modules.ModuleClassLoader
ModuleClassLoader for Module "org.jboss.jboss-transaction-spi:main" from local module loader @4b436982 (roots: c:\java\jboss-as-7\modules)
和它的getClass()。getInterfaces()[0] / * ==接口javax.transaction.UserTransaction * /。getClassLoader()是
ModuleClassLoader for Module "javax.transaction.api:main" from local module loader @4b436982 (roots: c:\java\jboss-as-7\modules)
但是,UserTransaction.class.getClassLoader()的类型为sun.misc.Launcher $ AppClassLoader。

jboss-modules.jar调用

通过org.jboss.modules.Main.main(即java -jar jboss-modules.jar也使用类路径)调用

C:\java\jboss-as-7\jboss-modules.jar

上面的系统属性和参数

-mp "C:\java\jboss-as-7\modules;C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules"
test.helloworld.client

它在createEJBContainer中失败了:

javax.ejb.EJBException: Unable to instantiate container with factories []
    at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:97)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:42)
    at test.helloworld.client.HelloWorldEmbeddedEjbTestClient.main(HelloWorldEmbeddedEjbTestClient.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.jboss.modules.Module.run(Module.java:260)
    at org.jboss.modules.Main.main(Main.java:291)

调试显示发生这种情况是因为在方法EJBContainer.findAllFactories()中,在线程上下文类加载器中找不到资源“META-INF / services / javax.ejb.spi.EJBContainerProvider”,这是 ModuleClassLoader for Module "test.helloworld.client:main" from local module loader @1afec586 (roots: C:\java\jboss-as-7\modules,C:\eclipse\projects\HelloWorldSlSB-Client\rt\modules)

问题

  • 有没有人知道如何解决这个问题或者有类似的工作?
  • 正常的JBoss安装是正确的起点,还是我需要特定的可嵌入变体?
  • UserTransaction甚至可以在嵌入场景中使用吗?
    • 如果是,那是否意味着我还可以为JPA 2 CMT实体和遗留JDBC代码使用一个XA数据源?两者都可以参与同一个事务(例如,JDBC代码使用java.sql.Connection.setAutoCommit(false)启动tx,然后使用TransactionAttributeType.REQUIRED调用EJB)?
  • 有人能指点我一些文件吗?所有我发现的是关于JBoss特定API的旧东西,而不是标准的EJB 3.1方式。
    • 最好记录如何在没有任何测试框架的情况下使用,因为我正在评估它用于生产用途。

感谢您阅读所有(或部分:-) this!

1 个答案:

答案 0 :(得分:2)

在记住我读过META-INF/services need to be imported explicitly之后,我找到了JBoss Modules方法的解决方案。因此,客户端的module.xml需要services="import",现在看起来像这样:

C:\蚀\项目\ HelloWorldSlSB客户端\室温\模块\测试\的HelloWorld \客户\主\ module.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<module xmlns="urn:jboss:module:1.1" name="test.helloworld.client">
    <main-class name="test.helloworld.client.HelloWorldEmbeddedEjbTestClient"/>

    <resources>
        <resource-root path="HelloWorldSlSB-Client.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.ejb.api"/>
        <module name="org.jboss.as.embedded" services="import"/>
        <module name="org.jboss.logmanager"/>
        <module name="test.helloworld"/>
    </dependencies>
</module>

此外,一条错误消息告诉我将系统属性java.util.logging.manager设置为org.jboss.logmanager.LogManager,因此我添加了相应的-D VM参数。然后来了ClassNotFoundException: org.jboss.logmanager.LogManager,所以我在上面添加了logmanager依赖。

仅将EJB jar放入createEJBContainer Map参数对于客户端来说是不够的,因此看起来EJB也必须是客户端可以明确依赖的模块(<module name="test.helloworld"/>以上)。所以我将HelloWorld-API.jar和HelloWorld-EJB.jar移动到目录 modulePath / test / helloworld / main /(即C:\ eclipse \ projects \ HelloWorldSlSB-Client \ rt \ modules \ test \ helloworld \ main),相应更改了new File("./HelloWorld-EJB.jar")中的路径,并为它们添加了一个module.xml:

C:\蚀\项目\ HelloWorldSlSB客户端\室温\模块\测试\ HelloWorld的\主\ module.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<module xmlns="urn:jboss:module:1.1" name="test.helloworld">
    <resources>
        <resource-root path="HelloWorld-API.jar"/>
        <resource-root path="HelloWorld-EJB.jar"/>
    </resources>
</module>

我从EJB jar中删除了test/helloworld/api/HelloWorld.class。没必要,但可能更清洁。

修改2013-02-27 : 发现一个更简单的工作调用,仍然使用org.jboss.modules.Main,但部署了EJB,因为我们可能会为非嵌入式使用而不需要module.xml文件。 no-arg createEJBContainer()现在已经足够了,因为我在-cp参数中包含了EJB jar。

%JBOSS_HOME%\ standalone \ deployments包含

HelloWorld-API.jar
HelloWorld-EJB.jar

的HelloWorld-EJB.jar:

META-INF/MANIFEST.MF
META-INF/jboss-deployment-structure.xml
test/helloworld/impl/HelloWorldBean.class

的HelloWorld-EJB.jar:META-INF / JBoss的部署-structure.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="deployment.HelloWorld-API.jar"/>
        </dependencies>
        <exclusions>
            <module name="Classpath"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

调用:

C:\java\jdk1.7\bin\java -Xmx512m -XX:MaxPermSize=256m -Duser.language=en
-Djboss.home=c:/java/jboss-as-7 -Djboss.home.dir=c:/java/jboss-as-7
-Djava.util.logging.manager=org.jboss.logmanager.LogManager
-classpath "C:\java\jboss-as-7\jboss-modules.jar"
org.jboss.modules.Main
-mp "C:\java\jboss-as-7\modules"
-dep "javax.ejb.api, org.jboss.as.embedded, org.jboss.logmanager"
-cp "C:\eclipse\output\HelloWorldSlSB-Client;C:\java\jboss-as-7\standalone\deployments\HelloWorld-API.jar;C:\java\jboss-as-7\standalone\deployments\HelloWorld-EJB.jar"
test.helloworld.client.HelloWorldEmbeddedEjbTestClient

目录C:\ eclipse \ projects \ HelloWorldSlSB-Client \ rt \ modules:为空,不再使用。

编辑完结2013-02-27

剩下的问题

  • 如果有人知道如何在没有运行org.jboss.modules.Main的情况下进行直接调用,我仍然想知道。
  • 文档链接仍然非常受欢迎。
  • UserTransaction / JDBC问题
BTW,也许名声不好的人可以添加像jboss-modules这样的标签?