【问题标题】:Issue with application where EJB connection is left open and subsequent connections are opened and closedEJB 连接处于打开状态且后续连接打开和关闭的应用程序出现问题
【发布时间】:2017-05-15 20:39:44
【问题描述】:

在打开和关闭其他 ejb 连接时保持和打开 ejb 连接是常见的还是可以接受的,还是应该在客户端完成连接并为后续任务打开一个新连接后立即关闭连接?

我目前正在开发一个使用 EJB (JBoss AS 7.1.1.final) 的 Swing 应用程序。应用程序打开一个 ejb 连接(即创建一个 InitialContext 实例),然后只要应用程序保持运行,就将该 InitialContext 用于常见任务。有许多长时间运行的操作会创建额外的 ejb 连接(和 InitialContext)。此连接用于单个长时间运行的进程,然后关闭。

在 JBoss 上,打开和关闭大约第 40 个连接后,我得到如下所示的异常。

2017 May 15, 16:29:03 INFO  - (JBossEJBClient.java:121) initialize - JNDI context initialized. 
java.lang.IllegalStateException: No EJB receiver available for handling [appName:dtsjboss,modulename:dtsserverejb,distinctname:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@4e692639
    at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:584)
    at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:119)
    at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:181)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:136)
    at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:121)
    at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:104)
    at com.sun.proxy.$Proxy4.getAuthorities(Unknown Source)
    at com.apelon.dts.examples.errors.ejb.EjbConnectionNotClosedErrorExample.doTest(EjbConnectionNotClosedErrorExample.java:53)
    at com.apelon.dts.examples.errors.ejb.EjbConnectionNotClosedErrorExample.bothCasesShouldSucceed(EjbConnectionNotClosedErrorExample.java:34)
    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:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

如果我运行下面的代码,使用和关闭 ejb 连接的情况有效,但单个连接保持打开的情况会因上述堆栈跟踪而失败。

package com.myCompany.myApp.examples.errors.ejb;

import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import org.apache.log4j.Logger;
import org.junit.Test;

import com.myCompany.myApp.client.jboss.JBossEJBClient;
import com.myCompany.myApp.dao.client.myAppServiceClient;
import com.myCompany.myApp.dao.client.myAppServiceClientParams;
import com.myCompany.myApp.testing.util.logging.LoggerForIntegrationTests;
import com.myCompany.myAppserver.dao.remote.AuthorityDao;
import com.myCompany.myAppserver.types.TAuthority;
import com.myCompany.install.util.ejb.ejbclient.myAppServiceClientFactory;

public class EjbConnectionNotClosedErrorExample {

    private static Logger logger = LoggerForIntegrationTests.get();

    private static final int COUNT = 100;

    @Test
    public void bothCasesShouldSucceed() {
        try {
            logger.debug("Doing case that works");
            doTest(true);
            logger.debug("Done with case that works.");
            logger.debug("\n\n\n");
            logger.debug("********************* DOING CASE THAT FAILS *********************");
            doTest(false);
            logger.debug("Done with use case that didn't work.");
        } catch (Exception exp) {
            exp.printStackTrace();
            throw new RuntimeException(exp);
        }
    }

    private void doTest(boolean closeConnection) {
        myAppServiceClientParams params = myAppServiceClientFactory.getDefaultClientParams();
        JBossEJBClient blocker = new JBossEJBClient();
        blocker.initialize(params);
        if (closeConnection == true) {
            blocker.close();
        }
        int max = COUNT;
        for (int i = 0; i < max; i++) {
            myAppServiceClient client = myAppServiceClientFactory.getDefaultClient();
            AuthorityDao dao = client.createAuthorityDao();
            List<TAuthority> list = dao.getAuthorities();
            logger.debug("CONNECTION " + (i + 1) + " ------------------------------------------------");
            logger.debug("Got " + list.size() + " authorities.");
            client.close();
        }
        System.out.println("");
    }

    public void initialize(myAppServiceClientParams params) {
        this.initialize(params.getHost(), params.getPort(), params.getInstance(), params.getUid(), params.getPwd());
    }

    public void initialize(String host, int port, String instance, String user, String password) {
        final Properties jndiProperties = new Properties();
        String providerURL = "remote://" + host + ":" + port;
        jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, org.jboss.naming.remote.client.InitialContextFactory.class.getName());
        jndiProperties.put(Context.PROVIDER_URL, providerURL);
        jndiProperties.put("jboss.naming.client.ejb.context", true);
        jndiProperties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
        // Explicitly specify STARTTLS = false for connecting to Wildfly v10
        jndiProperties.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS", "false");
        jndiProperties.put(Context.SECURITY_PRINCIPAL, user);
        jndiProperties.put(Context.SECURITY_CREDENTIALS, password);
        try {
            InitialContext ctx = new InitialContext(jndiProperties);
            ctx.getEnvironment();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

这是 JBoss AS 7.1.1.final 特有的错误吗?

【问题讨论】:

  • 我见过防火墙在一段时间后像这样断开连接。
  • 它可能有几个问题: 1# 连接:连接断开 2# 安全性:用户/密码无效 3# EJB 缺失:已连接,但 ejb 不存在 4# SSL JBoss 与其他服务器,因此当客户端看到此消息时,意味着没有连接到具有您尝试调用的 ejb 的服务器,因此当与其他服务器的连接失败时将记录一条消息。
  • @SteveC:我认为这不是这里发生的事情,因为 JUnit 测试会在大约一秒钟内执行。
  • @AnupDey:这可能不是您列出的任何因素,因为我在连接失败之前成功连接到实例超过 100 次。
  • 查找ejb后通过context.close()检查是否关闭了Initialcontext,就不会再有问题了。

标签: jboss ejb


【解决方案1】:

这里的问题是单个连接被应用程序的主线程打开并用作资源,这(出于某种原因)导致 JBoss 没有完全取消分配其他连接。解决方案是在打开此连接时获取对它的引用,然后在创建任何其他新连接之前关闭此连接,然后在创建新连接后立即重新打开主线程正在使用的连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    相关资源
    最近更新 更多