• Jboss EAP 6 EJB调用常见问题


    1. 调用EJB的三种方法

    调用EAP 6 EJB的第一种方法,使用JBoss API,如下:

    Java代码 复制代码 收藏代码
    1. Properties p = new Properties();  
    2. p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");  
    3. p.put("remote.connections", "default");  
    4. p.put("remote.connection.default.host", "localhost");  
    5. p.put("remote.connection.default.port", "4447");  
    6. p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");  
    7.   
    8. EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);  
    9. ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);  
    10. EJBClientContext.setSelector(selector);  
    11.   
    12. Properties props = new Properties();  
    13. props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");  
    14. InitialContext context = new InitialContext(props);  
    15.   
    16. final boolean useScopedExample = Boolean.getBoolean("UseScopedContext");  
    17. final String rcal = "ejb:jboss-ejb-multi-server-app-main/ejb//" + (useScopedExample ? "MainAppSContextBean" : "MainAppBean") + "!" + MainApp.class.getName();  
    18. final MainApp remote = (MainApp) context.lookup(rcal);  
    Properties p = new Properties();
    p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
    p.put("remote.connections", "default");
    p.put("remote.connection.default.host", "localhost");
    p.put("remote.connection.default.port", "4447");
    p.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
    
    EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
    ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
    EJBClientContext.setSelector(selector);
    
    Properties props = new Properties();
    props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    InitialContext context = new InitialContext(props);
    
    final boolean useScopedExample = Boolean.getBoolean("UseScopedContext");
    final String rcal = "ejb:jboss-ejb-multi-server-app-main/ejb//" + (useScopedExample ? "MainAppSContextBean" : "MainAppBean") + "!" + MainApp.class.getName();
    final MainApp remote = (MainApp) context.lookup(rcal);

    这种方法在Standalone client (client is not running inside of JBoss EAP 6)能正常调用,但在EAP 6环境中会报java.lang.SecurityException: EJBCLIENT000021: EJB client context selector may not be changed。

    第二种方法使用scoped context,代码如下:

    Java代码 复制代码 收藏代码
    1. Properties props = new Properties();  
    2. props.put("org.jboss.ejb.client.scoped.context", "true");  
    3. props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");  
    4. //props.put(Context.OBJECT_FACTORIES, "org.jboss.ejb.client.naming.ejb.ejbURLContextFactory");  
    5. props.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");  
    6. props.put("remote.connections", "default");  
    7. props.put("remote.connection.default.port", 4447);  
    8. props.put("remote.connection.default.host", host);  
    9. //props.put("remote.connection.default.username", username);  
    10. //props.put("remote.connection.default.password", password);  
    11. props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");  
    12. props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");  
    13.   
    14. Context context = (Context) new InitialContext(props).lookup("ejb:");  
    15. try {  
    16.    final TimerExample bean = (TimerExample) context.lookup("TestTimer/TestTimerEJB/TimerExampleBean!org.example.jboss.timer.TimerExample");  
    17.    bean.doSomething();  
    18. finally {  
    19.    try {   
    20.        context.close();  
    21.    } catch(Exception e) { }  
    22. }   
    Properties props = new Properties();
    props.put("org.jboss.ejb.client.scoped.context", "true");
    props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    //props.put(Context.OBJECT_FACTORIES, "org.jboss.ejb.client.naming.ejb.ejbURLContextFactory");
    props.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
    props.put("remote.connections", "default");
    props.put("remote.connection.default.port", 4447);
    props.put("remote.connection.default.host", host);
    //props.put("remote.connection.default.username", username);
    //props.put("remote.connection.default.password", password);
    props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
    props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
    
    Context context = (Context) new InitialContext(props).lookup("ejb:");
    try {
       final TimerExample bean = (TimerExample) context.lookup("TestTimer/TestTimerEJB/TimerExampleBean!org.example.jboss.timer.TimerExample");
       bean.doSomething();
    } finally {
       try { 
           context.close();
       } catch(Exception e) { }
    } 

    这种方式,可以完全通过代码实现配置,但由客户端来创建和管理Connection,因此需要更多的资源,性能不高。还有一个严重的问题,当使用CMT,事物跨多个EJB时,因每次调用EJB后都关闭context(如不close,connection会一直保持),这将造成事务commit/rollback失败。这种情况下,就得使用第三种方式,也是推荐的方式:

    先来看代码:

    Java代码 复制代码 收藏代码
    1. Properties props = new Properties();  
    2. props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");  
    3. final Context context = new javax.naming.InitialContext(props);  
    4. final Greeter bean = (Greeter) context.lookup("ejb:myapp/myejb/GreeterBean!" + org.myapp.ejb.Greeter.class.getName());  
    5. bean.doSometing();  
    Properties props = new Properties();
    props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    final Context context = new javax.naming.InitialContext(props);
    final Greeter bean = (Greeter) context.lookup("ejb:myapp/myejb/GreeterBean!" + org.myapp.ejb.Greeter.class.getName());
    bean.doSometing();

     代码很简单,注意没有调用close()方法。那这是怎么找到远程主机的呢?需要增加一些配置,先在war的WEB-INF或ear的META-INF中新建一个文件jboss-ejb-client.xml,内容如下:

    Xml代码 复制代码 收藏代码
    1. <jboss-ejb-client xmlns="urn:jboss:ejb-client:1.2">  
    2.     <client-context>  
    3.         <ejb-receivers>  
    4.             <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-app1" connect-timeout="10000"/>  
    5.             <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-app2" connect-timeout="10000"/>  
    6.         </ejb-receivers>  
    7.     </client-context>  
    8. </jboss-ejb-client>  
    <jboss-ejb-client xmlns="urn:jboss:ejb-client:1.2">
        <client-context>
            <ejb-receivers>
                <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-app1" connect-timeout="10000"/>
                <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-app2" connect-timeout="10000"/>
            </ejb-receivers>
        </client-context>
    </jboss-ejb-client>

     然后在standalone.xml增加如下配置,建立与远程主机的关联:

    Xml代码 复制代码 收藏代码
    1. <subsystem xmlns="urn:jboss:domain:remoting:1.2">  
    2.     <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>  
    3.     <outbound-connections>  
    4.         <remote-outbound-connection name="remote-ejb-connection-app1" outbound-socket-binding-ref="remote-ejb-app1">  
    5.             <properties>  
    6.                 <property name="SASL_POLICY_NOANONYMOUS" value="false"/>  
    7.                 <property name="SSL_ENABLED" value="false"/>  
    8.             </properties>  
    9.         </remote-outbound-connection>  
    10.         <remote-outbound-connection name="remote-ejb-connection-app2" outbound-socket-binding-ref="remote-ejb-app2">  
    11.             <properties>  
    12.                  <property name="SASL_POLICY_NOANONYMOUS" value="false"/>  
    13.                  <property name="SSL_ENABLED" value="false"/>  
    14.             </properties>  
    15.         </remote-outbound-connection>  
    16.     </outbound-connections>  
    17. </subsystem>  
    18.   
    19. ...  
    20.   
    21. <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">  
    22.     <outbound-socket-binding name="remote-ejb-app1">  
    23.         <remote-destination host="localhost" port="4447"/>  
    24.     </outbound-socket-binding>  
    25.     <outbound-socket-binding name="remote-ejb-app2">  
    26.         <remote-destination host="localhost" port="4447"/>  
    27.     </outbound-socket-binding>  
    28. </socket-binding-group>  
    <subsystem xmlns="urn:jboss:domain:remoting:1.2">
        <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
        <outbound-connections>
            <remote-outbound-connection name="remote-ejb-connection-app1" outbound-socket-binding-ref="remote-ejb-app1">
                <properties>
                    <property name="SASL_POLICY_NOANONYMOUS" value="false"/>
                    <property name="SSL_ENABLED" value="false"/>
                </properties>
            </remote-outbound-connection>
            <remote-outbound-connection name="remote-ejb-connection-app2" outbound-socket-binding-ref="remote-ejb-app2">
                <properties>
                     <property name="SASL_POLICY_NOANONYMOUS" value="false"/>
                     <property name="SSL_ENABLED" value="false"/>
                </properties>
            </remote-outbound-connection>
        </outbound-connections>
    </subsystem>
    
    ...
    
    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <outbound-socket-binding name="remote-ejb-app1">
            <remote-destination host="localhost" port="4447"/>
        </outbound-socket-binding>
        <outbound-socket-binding name="remote-ejb-app2">
            <remote-destination host="localhost" port="4447"/>
        </outbound-socket-binding>
    </socket-binding-group>

     调用EJB后,来查看一下connection情况:netstat -aon | findstr "4447"(netstat -np | grep 4447)

    2. Could not register a EJB receiver: java.lang.RuntimeException: Operation failed with status WAITING

    EJB调用配置中包含以下三个timeout参数:

    • invocation.timeout

    The timeout for the EJB handshake or method invocation request/response cycle. The value is in milliseconds. The invocation of any method throws a java.util.concurrent.TimeoutException if the execution takes longer than the timeout period. The execution completes and the server is not interrupted.

    • reconnect.tasks.timeout

    The timeout for the background reconnect tasks. The value is in milliseconds. If a number of connections are down, the next client EJB invocation will use an algorithm to decide if a reconnect is necessary to find the right node.

    • remote.connection.CONNECTION_NAME.connect.timeout

    The timeout period for the initial connection. After that, the reconnect task will periodically check whether the connection can be established. The value is in milliseconds.

    remote.connection.CONNECTION_NAME.connect.timeout默认值为5000ms(参见代码InitialContextFactory.getInitialContext),当在timeout时间内连接不上时,就会报以上错误。

    3. 关于Rollback

    EJB方法抛出RuntimeException会引起rollback,那有方法指定某个Exception是否引起Rollback么?可以使用注解@ApplicationException,如下:

    @ApplicationException(rollback = true)

    public class MyException extends Exception {     // ... }

    4. How to close scoped EJB client contexts?

    Internally, when a lookup happens for a ejb: URL string, a relevant javax.naming.Context is created for that ejb: lookup.

    So we first create a JNDI context and then use it to lookup an EJB.

    Java代码 复制代码 收藏代码
    1. final Properties props = new Properties();  
    2. // mark it for scoped EJB client context  
    3. props.put("org.jboss.ejb.client.scoped.context","true");  
    4. // add other properties  
    5. props.put(....);  
    6. ...  
    7. Context jndiCtx = new InitialContext(props);  
    8. Context ejbRootNamingContext = (Context) jndiCtx.lookup("ejb:");  
    9. try {  
    10.     final MyBean bean = ejbRootNamingContext.lookup("app/module/distinct/bean!interface"); // rest of the EJB jndi lookup string  
    11.     bean.doSomething();  
    12. finally {  
    13.     try {  
    14.         // close the EJB naming JNDI context  
    15.         ejbRootNamingContext.close();  
    16.     } catch (Throwable t) {  
    17.         // log and ignore  
    18.     }  
    19.     try {  
    20.         // also close our other JNDI context since we are done with it too  
    21.         jndiCtx.close();  
    22.     } catch (Throwable t) {  
    23.         // log and ignore  
    24.     }  
    25.    
    26. }  
    final Properties props = new Properties();
    // mark it for scoped EJB client context
    props.put("org.jboss.ejb.client.scoped.context","true");
    // add other properties
    props.put(....);
    ...
    Context jndiCtx = new InitialContext(props);
    Context ejbRootNamingContext = (Context) jndiCtx.lookup("ejb:");
    try {
        final MyBean bean = ejbRootNamingContext.lookup("app/module/distinct/bean!interface"); // rest of the EJB jndi lookup string
        bean.doSomething();
    } finally {
        try {
            // close the EJB naming JNDI context
            ejbRootNamingContext.close();
        } catch (Throwable t) {
            // log and ignore
        }
        try {
            // also close our other JNDI context since we are done with it too
            jndiCtx.close();
        } catch (Throwable t) {
            // log and ignore
        }
     
    }

    Invoking Session Beans

    Scoped EJB client contexts

    How to configure an EJB client in JBoss EAP 6

  • 相关阅读:
    vue双向绑定的时候把遍历的数组转为了字符串,并且再转回去数组进行绑定
    使用for of循环遍历获取的nodeList,配置babel编译,webpack打包之后在iphone5下报错
    iview表单验证不生效问题注意点
    babel配置项目目录支持转换es6语法,引入非项目目录js后,引入Js转换无效
    swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction
    移动网页广告引入mraid.js使用指南
    react项目和next项目修改默认端口号
    windows安装mongodb服务简洁版教程
    Fiddler抓包手机代理配置
    手机配置代理报错invalid host header
  • 原文地址:https://www.cnblogs.com/firstdream/p/9796234.html
Copyright © 2020-2023  润新知