首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么DirContext.close()不将LDAP连接返回到池中?

为什么DirContext.close()不将LDAP连接返回到池中?
EN

Stack Overflow用户
提问于 2012-08-14 14:53:25
回答 2查看 10.6K关注 0票数 8

我注意到在使用LDAP连接池时,尽管文档化了close() saying otherwise,但在上下文中调用它似乎没有返回到池中。因此,当我尝试从池中获取一个项目时,当它已经达到最大大小时,它就挂起了。

我设法把它缩小到最低限度。尽管我认为我确实在所有相关对象上调用close(),但它似乎依赖于垃圾收集来将对象实际返回到池中,这是出乎意料的。为什么会发生这种事?还有其他我应该关闭的对象吗?

在下面的代码片段中:

  • 我已经人为地设置了最大池大小为1,以突出问题。
  • 我从池(第(2)行)获得一个DirContext,尝试将它返回到池(第(4)行),然后从池(第(6)行)获得另一个应该返回相同的返回对象。
  • 相反,第二个请求(行(6))挂起对Object.wait()的一些内部调用。我猜它是在等待一个集合对象变得可用。
  • 如果通过注释(1)关闭池,它不会挂起(但是我想要池!)。
  • 如果我注释掉(3) --给SearchResults.next()的电话--它可以正常工作。
  • 如果我取消注释行(5),强制在“返回池”调用和向池请求新对象之间强制垃圾收集,则不会挂起。

由于注释行(3)使问题消失,也许我没有正确地关闭它的返回值,而且它正在保持池连接处于打开状态。但是,在本例中,方法results.next()返回一个SearchResult,它没有close方法,也没有关于如何干净地关闭它的文档的指导。

测试用例:

代码语言:javascript
复制
@Test
public void testHangs() throws NamingException {

    System.setProperty("com.sun.jndi.ldap.connect.pool.debug", "fine");
    System.setProperty("com.sun.jndi.ldap.connect.pool.maxsize", "1");

    Hashtable<String,String> env = new Hashtable<String,String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.SECURITY_PRINCIPAL, user);
    env.put(Context.SECURITY_CREDENTIALS, passwd);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.PROVIDER_URL, ldapUrl);

    // use a connection pool
    env.put("com.sun.jndi.ldap.connect.pool", "true"); // -----------------  (1)

    // get a context from the pool.
    DirContext context = new InitialDirContext(env); // -------------------- (2)
    NamingEnumeration<SearchResult> results = context.search("", query, getSC());
    // obviously the next two lines would normally be in a 
    // while(results.hasMore()) { ... = results.next(); } loop.
    assertTrue(results.hasMore()); // this is only a problem when there are some results.
    results.next(); // ----------------------------------------------------- (3)

    // ensure the context is returned to the pool.
    results.close();
    context.close(); // ---------------------------------------------------- (4)

    //System.gc(); // ------------------------------------------------------ (5)

    new InitialDirContext(env);  // hangs here! ---------------------------- (6)
}

使用代码,我的控制台显示:

代码语言:javascript
复制
Create com.sun.jndi.ldap.LdapClient@1a7bf11[ldapad:389]
Use com.sun.jndi.ldap.LdapClient@1a7bf11

然而,如果我强制GC,我还会看到:

代码语言:javascript
复制
Release com.sun.jndi.ldap.LdapClient@93dee9 <-- on GC
Use com.sun.jndi.ldap.LdapClient@93dee9     <-- on new InitialDirContext
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-15 08:58:18

经过一番调查,我发现LDAP连接没有返回到池中,因为SearchResult对象包含对LdapCtx对象的引用。

如果你换掉

代码语言:javascript
复制
results.next();

使用以下内容

代码语言:javascript
复制
SeachResult ob = results.next();
((Context)ob.getObject()).close();

连接将正确地返回到池中。这似乎是默认实现中的一个bug。

使用Spring时不存在这个问题,因为它在环境中提供了一个自定义的"java.naming.factory.object“,作为构建SearchResult过程的一部分关闭了LdapCtx。通过将Spring库添加到类路径并将以下内容添加到InitialContext中,可以轻松地演示

java.naming.factory.object=org.springframework.ldap.core.support.DefaultDirObjectFactory

完成此操作后,由com.sun.jndi.ldap.LdapCtx:com.sun.jndi.ldap.LdapCtx保存的SearchResult对象将更改为org.springframework.ldap.core.DirContextAdapter.DefaultDirObjectFactory类负责创建DirContextAdapter,并在将DirContextAdapter返回给DirectoryManager之前注意关闭LdapCtx。下面是DefaultDirObjectFactory的最后一个块

代码语言:javascript
复制
finally {
        // It seems that the object supplied to the obj parameter is a
        // DirContext instance with reference to the same Ldap connection as
        // the original context. Since it is not the same instance (that's
        // the nameCtx parameter) this one really needs to be closed in
        // order to correctly clean up and return the connection to the pool
        // when we're finished with the surrounding operation.
        if (obj instanceof Context) {

            Context ctx = (Context) obj;
            try {
                ctx.close();
            }
            catch (Exception e) {
                // Never mind this
            }

        }
    }
票数 8
EN

Stack Overflow用户

发布于 2012-08-15 11:06:00

SearchControls对象更改为returningObjFlag属性为false。通常不需要对象本身,只需要它的nameInNamespace和它的属性。只有当要创建或修改子上下文时,才需要对象本身。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11955041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档