【问题标题】:WildFly: EJB invocations from a remote clientWildFly:来自远程客户端的 EJB 调用
【发布时间】:2014-01-16 00:30:45
【问题描述】:

我试图在 WildFly 中查找并调用部署为 EAR 的 EJB。我尝试了不同的方法。

Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");        
properties.put(Context.PROVIDER_URL, "remote://localhost:4447");
properties.put(Context.SECURITY_PRINCIPAL, myUser);
properties.put(Context.SECURITY_CREDENTIALS, myPassword);    
properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

InitialContext context = new InitialContext(properties);
Object object = context.lookup(jndi);
MyService service = (MyService)object;
System.out.println(service.echo("JYM"));

它已经抛出:

javax.naming.NamingException: Failed to connect to any server. Servers tried: [remote://localhost:4447]
    at org.jboss.naming.remote.client.HaRemoteNamingStore.failOverSequence(HaRemoteNamingStore.java:213)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.namingStore(HaRemoteNamingStore.java:144)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.namingOperation(HaRemoteNamingStore.java:125)
    at org.jboss.naming.remote.client.HaRemoteNamingStore.lookup(HaRemoteNamingStore.java:241)
    at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:79)
    at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:83)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at com.app.test.service.MyServiceTest.echo(MyServiceTest.java:60)

如果我添加以下属性:

properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
properties.put("jboss.ejb.client.scoped.context", "true");

我收到了:

java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:roolafic, moduleName:usermanagement, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@3c0f93f1
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:749)
    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:116)
    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:183)
    at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:253)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:198)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:181)
    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:144)
    at com.sun.proxy.$Proxy4.echo(Unknown Source)
    at com.app.test.service.MyServiceTest.echo(MyServiceTest.java:62)

然后我看到一个Jboss forum post,它说使用http-remoting 而不是remote。但这也没有用。即使使用端口 8080。

我已经尝试过here提到的方式。但它似乎不适用于我的情况。虽然我已将 jboss-ejb-client.properties 放在我从 Eclipse 运行客户端方法的同一目录中。

【问题讨论】:

    标签: java jboss java-ee-7 wildfly ejb-3.2


    【解决方案1】:

    花了将近半天的时间后,我找到了解决方案。这里是:

    public static <T> T connectEJB(String jndi) throws NamingException {
        Properties clientProperties = new Properties();
        clientProperties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
        clientProperties.put("remote.connections", "default");
        clientProperties.put("remote.connection.default.port", myPort);
        clientProperties.put("remote.connection.default.host", myHost);
        clientProperties.put("remote.connection.default.username", myUser);
        clientProperties.put("remote.connection.default.password", myPassword);
        clientProperties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
    
        EJBClientConfiguration ejbClientConfiguration = new PropertiesBasedEJBClientConfiguration(clientProperties);
        ContextSelector<EJBClientContext> contextSelector = new ConfigBasedEJBClientContextSelector(ejbClientConfiguration);
        EJBClientContext.setSelector(contextSelector);
    
        Properties properties = new Properties();
        properties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        Context context = new InitialContext(properties);
        return (T) context.lookup(jndi);
    }
    

    有关详细信息,请参阅here。 希望对其他人有所帮助。

    【讨论】:

    • 这个的默认端口是什么?
    • @IsuruGunawardana 默认情况下,Wildfly 在端口 8080 上运行
    【解决方案2】:

    我在 Wildfly 10 上遇到了同样的异常。

    同时遵循一些重要的参考:

    即关于在以下位置建立远程 EJB 连接的文档: https://docs.jboss.org/author/display/WFLY10/EJB+invocations+from+a+remote+client+using+JNDI

    java.lang.IllegalStateException:EJBCLIENT000025:

    没有 EJB 接收器可用于处理 [appName:, 模块名称:wildfly10-test-client-remote-ejb,distinctName:] 调用上下文的组合 org.jboss.ejb.client.EJBClientInvocationContext@1b26f7b2 在 org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798) 在 org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:128) 在 org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186) 在 org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255) 在 org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200) 在 org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183) 在 org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146) 在 com.sun.proxy.$Proxy6.doWork(Unknown Source) 在 ejb.InvokeRemoteEjbTest.testThatFailsWithEJBCLIENT000025(InvokeRemoteEjbTest.java:90)

      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at
    

    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

    但这个测试异常并不孤单,我在控制台上也有以下异常:

    NFO:XNIO 版本 3.3.4.Final 2017 年 2 月 13 日 12:42:28 PM org.xnio.nio.NioXnio INFO:XNIO NIO 实现版本 3.3.4.Final 2017 年 2 月 13 日 12:42:28 PM org.jboss.remoting3.EndpointImpl 信息:JBoss Remoting 版本 4.0.18.Final 2017 年 2 月 13 日 12:42:28 PM org.jboss.ejb.client.EJBClient 信息:JBoss EJB 客户端版本 2.1.4.Final 2017 年 2 月 13 日 12:42:28 PM org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector setupEJBReceivers 警告:无法为 EJB 接收器注册 连接到 localhost:4447 java.io.EOFException: XNIO000812: 连接意外关闭 org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:416) 在 org.xnio.http.HttpUpgrade$HttpUpgradeState$UpgradeResultListener.handleEvent(HttpUpgrade.java:400) 在 org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) 在 org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) 在 org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:88) 在 org.xnio.nio.WorkerThread.run(WorkerThread.java:559) 在 ...异步调用...(未知来源)在 org.jboss.remoting3.EndpointImpl.doConnect(EndpointImpl.java:294) 在 org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:416) 在 org.jboss.ejb.client.remoting.EndpointPool$PooledEndpoint.connect(EndpointPool.java:192) 在 org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:153) 在 org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:133) 在 org.jboss.ejb.client.remoting.ConnectionPool.getConnection(ConnectionPool.java:78) 在 org.jboss.ejb.client.remoting.RemotingConnectionManager.getConnection(RemotingConnectionManager.java:51)

    at org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.setupEJBReceivers(ConfigBasedEJBClientContextSelector.java:161)
    

    在 org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:118) 在 org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector.getCurrent(ConfigBasedEJBClientContextSelector.java:47) 在 org.jboss.ejb.client.EJBClientContext.getCurrent(EJBClientContext.java:281) 在 org.jboss.ejb.client.EJBClientContext.requireCurrent(EJBClientContext.java:291) 在 org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:178) 在 org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146) 在 com.sun.proxy.$Proxy6.doWork(Unknown Source) 在 ejb.InvokeRemoteEjbTest.testThatFailsWithEJBCLIENT000025(InvokeRemoteEjbTest.java:90)

      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at
    

    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

    关键点如下。 (1) Jboss 似乎有两个不同的代码层,它们的行为不同。 第一个是 JNDI 初始上下文,当您连接到“远程”端口(例如旧的传统端口 4447)时,它可以正常工作。

    因此,当您在 JNDI 上下文的代码中执行以下操作时:

    final Properties env = new Properties();
            env.put(Context.INITIAL_CONTEXT_FACTORY, org.jboss.naming.remote.client.InitialContextFactory.class.getName());
            env.put(Context.PROVIDER_URL, "remote://localhost:4447");            
    
            // why is this needed?
            // This is an important property to set if you want to do EJB invocations via the remote-naming project
            env.put("jboss.naming.client.ejb.context", true);
    
            // Lookup optimization for @Stateless EJBs.
            // https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project
            // section: Why use the EJB client API approach then?
            env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    
            // authenticate
            env.put(Context.SECURITY_PRINCIPAL, "adminUser");
            env.put(Context.SECURITY_CREDENTIALS, "adminPassword");
            initialContext = new InitialContext(env);
    

    您可以将远程 EJB 从服务器中取出,您已经拥有了代理。 真正出错的地方是,当您使用 proxu 并执行以下操作时:

    remoteEJB.doWorkg();
    

    出现这种情况是因为代理上的 Lookup 逻辑和 execute 逻辑并不完全相同,即执行逻辑正在寻找这些:

    “没有可用于处理的 EJB 接收器”

    基于配置文件: "jboss-ejb-client.properties"

    你应该在你的类路径中运行你的系统测试。或者您的客户端应用程序。

    现在,当您执行此操作时: jboss-ejb-client.properties

    您可以尝试配置您的“远程处理”端口 4447,但这会非常错误,因为您不再使用现代远程 EJB 客户端;

     <dependency>
            <groupId>org.wildfly</groupId>
            <artifactId>wildfly-ejb-client-bom</artifactId>
            <version>10.0.0.Final</version>
            <type>pom</type>
            <scope>test</scope>
        </dependency>
    

    此客户端希望您的 wildfly 10 配置为今天的默认配置,可以从普通 HTTP 套接字提供远程处理。 因此,它希望对 TCP 进行 HTTP 套接字升级,就像 Web 套接字发生的那样。 这不适用于您的:4447 套接字,它从来就不是 http 套接字。

    所以当我最后去看看远程子系统是如何配置的时,我需要用以下内容来增加它:

      <subsystem xmlns="urn:jboss:domain:remoting:3.0">
                <endpoint/>
                <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
                <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
            </subsystem>
    

    http-connector 是新增的。 现在,就 JNDI 初始上下文设置而言,我使用端口 4447 还是 8080 都没有关系,两者都可以工作。 为了保持一致,我不使用仍然开放的 4447 端口,我使用 8080 端口。 但是,对于 8080 pot,您的提供商 URL 必须进行如下调整:

    env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
    

    我的建议是:为您的远程 ejb 子系统配置端口 4447 和 8080。 但是对于客户端连接使用端口 8080,用于 JNDI 查找和 EJB 执行。

    在这种情况下,wildfly 异常是无用的,它对开发人员找出问题所在没有多大帮助。

    这个问题的关键在于发现 HTTP 连接升级问题,并发现该行为对于套接字 4447 来说显然是错误的。

    最后,仅供参考。 你的 ejb-client.proeprties 文件应该是这样的:

    #QUOTE:
    #First the endpoint.name property. 
    #We mentioned earlier that the EJB receivers will communicate with the server for EJB invocations.
    #Internally, they use JBoss Remoting project to carry out the communication. 
    #The endpoint.name property represents the name that will be used to create the client side of the enpdoint. 
    # The endpoint.name property is optional and if not specified in the jboss-ejb-client.properties file, it will default to "config-based-ejb-client-endpoint" name.
    # https://docs.jboss.org/author/display/WFLY10/EJB+invocations+from+a+remote+client+using+JNDI
    endpoint.name=client-endpoint
    remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
    
    remote.connections=default
    
    remote.connection.default.host=localhost
    remote.connection.default.port=8080
    remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
    
    remote.connection.default.username=youAppServerAdmin
    remote.connection.default.password=youAppServerAdminPass
    

    要记住的关键是上述文件上的 PORT 应该是 HTTP 端口,而不是像 4447 这样的“远程”端口。 至少在 wildfly 10 中,对于旧版本我不确定。

    祝你好运。

    【讨论】:

      猜你喜欢
      • 2015-04-20
      • 1970-01-01
      • 2014-08-18
      • 2016-08-02
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多