bac*_*car 8 java jndi connection-pooling ldap
我同时使用LDAP连接,调用池注意到close()上下文却没有出现,返回到池尽管文件说 ,否则.因此,当我尝试从池中获取项目时,它已经处于最大大小,它会挂起.
我设法将其缩小到最小的情况.即使我相信我close()确定地调用了所有相关对象,但它似乎依赖于垃圾收集来实际将对象返回到池中,这是意料之外的.为什么会这样?还有其他一些我应该关闭的对象吗?
在下面的代码段中:
DirContext从池中得到一个(第(2)行),尝试将它返回到池(第(4)行),然后从池中获取另一个(第(6)行),它应返回相同的返回对象.Object.wait().我猜它正在等待一个池化对象变得可用.SearchResults.next()- 它运作正常.由于注释掉第(3)行会使问题消失,或许我没有正确地关闭它的返回值,并且它正在保持池连接打开.但是,在这种情况下,该方法results.next()返回a SearchResult,close在其文档中没有方法也没有关于如何干净地关闭它的指导.
测试用例:
@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)
}
Run Code Online (Sandbox Code Playgroud)
使用代码,我的控制台显示:
Create com.sun.jndi.ldap.LdapClient@1a7bf11[ldapad:389]
Use com.sun.jndi.ldap.LdapClient@1a7bf11
Run Code Online (Sandbox Code Playgroud)
如果我强制GC,我另外看到:
Release com.sun.jndi.ldap.LdapClient@93dee9 <-- on GC
Use com.sun.jndi.ldap.LdapClient@93dee9 <-- on new InitialDirContext
Run Code Online (Sandbox Code Playgroud)
小智 8
经过一些调查后,我发现LDAP连接没有返回到池中,因为SearchResult对象包含对LdapCtx对象的引用.
如果你更换
results.next();
Run Code Online (Sandbox Code Playgroud)
有以下几点
SeachResult ob = results.next();
((Context)ob.getObject()).close();
Run Code Online (Sandbox Code Playgroud)
连接将正确返回池中.这似乎是默认实现中的一个错误.
使用Spring LDAPTemplate时,问题不存在,因为它在关闭LdapCtx的环境中提供了一个自定义的"java.naming.factory.object",作为构建SearchResult过程的一部分.通过将Spring LDAP库添加到类路径并将以下内容添加到InitialContext,可以轻松地演示此内容
java.naming.factory.object = org.springframework.ldap.core.support.DefaultDirObjectFactory
完成此操作后,SearchResult持有的对象将从com.sun.jndi.ldap.LdapCtx:com.sun.jndi.ldap.LdapCtx更改为org.springframework.ldap.core.DirContextAdapter.该DefaultDirObjectFactory类是负责创建DirContextAdapter和照顾返回之前关闭LdapCtx DirContextAdapter到将DirectoryManager.这是DefaultDirObjectFactory的finally块
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9611 次 |
| 最近记录: |