【发布时间】:2019-12-16 01:58:02
【问题描述】:
我的 JNDI 连接池似乎没有按预期工作。当我运行我的测试时,我看到每次都会创建新的连接。连接成功(因为我可以很好地查询 Active Directory),但它们并没有像我期望的那样进行池化。以下是关于我的设置的一些重要说明:
连接正在通过 SSL(即 ldaps)
使用自定义套接字工厂
对 AD 的身份验证通过“简单”身份验证完成
使用默认池配置值(目前)
以下是相关代码:
TestLdapsPooling.java
public class TestLdapsPooling {
public static void main(String[] args) throws Exception {
// needed system properties
System.setProperty("com.sun.jndi.ldap.connect.pool.protocol", "ssl");
System.setProperty("com.sun.jndi.ldap.connect.pool.debug", "fine");
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, host);
// use ssl
env.put(Context.SECURITY_PROTOCOL, "ssl");
// authentication info
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
// custom socket factory
env.put("java.naming.ldap.factory.socket", "ldap.TrustedSocketFactory");
// Enable connection pooling
env.put("com.sun.jndi.ldap.connect.pool", "true");
// Create the initial context
InitialDirContext context = new InitialDirContext(env);
System.out.println("First context created");
// Create a second context
InitialDirContext context2 = new InitialDirContext(env);
System.out.println("Second context created");
// close first context
context.close();
System.out.println("First context closed");
// close second context
context2.close();
System.out.println("Second context closed");
// Create a third context - I would expect this to use a connection from the pool
InitialDirContext context3 = new InitialDirContext(env);
System.out.println("Third context created");
// close third context
context3.close();
System.out.println("Third context closed");
}
}
TrustedSocketFactory.java
public class TrustedSocketFactory extends SSLSocketFactory implements Comparator<SocketFactory> {
// all the methods required from SSLSocketFactory
@Override
public int compare(SocketFactory arg0, SocketFactory arg1) {
// not really sure what this value should be
// is this causing the pooling issue?
return 0;
}
}
输出:
Create com.sun.jndi.ldap.LdapClient@3f0ee7cb[testdomain.com:636]
Use com.sun.jndi.ldap.LdapClient@3f0ee7cb
First context created
Create com.sun.jndi.ldap.LdapClient@75bd9247[testdomain.com:636]
Use com.sun.jndi.ldap.LdapClient@75bd9247
Second context created
Release com.sun.jndi.ldap.LdapClient@3f0ee7cb
First context closed
Release com.sun.jndi.ldap.LdapClient@75bd9247
Second context closed
Create com.sun.jndi.ldap.LdapClient@7d417077[testdomain.com:636]
Use com.sun.jndi.ldap.LdapClient@7d417077
Third context created
Release com.sun.jndi.ldap.LdapClient@7d417077
Third context closed
我希望第三个上下文重用前两个连接之一,但输出看起来像是创建了自己的连接。为了重用连接而不是创建新连接,我需要进行哪些更改?
【问题讨论】:
-
你不会相信这一点,但这是一个有据可查的事实:启用连接池调试会禁用连接池。 NB 您为什么使用自定义套接字工厂?
-
我在某处看到了这样的评论,但我不敢相信。可笑和可悲的是,这是真的。我们正在使用自定义套接字工厂,以便我们可以轻松地自定义信任存储,而不会影响机器上甚至在同一应用程序中运行的其他 Java 服务。不确定这是否是最好的方法,但如果有更好的方法可以实现,请告诉我。
-
所有信任库问题的解决方案是让服务器使用 CA 签名的证书。
-
是的,我们这样做了,但是针对不同的用例有不同的 CA。换句话说,我们不会将所有受信任的证书放入一个大型信任库中,而是根据用例分解信任库。
-
我相信我弄错了,这没有记录在案,并且我在多年前面临同样问题时在源代码的评论中发现了它。我可能在 SO 上也提到过一两次。我没有看到不同信任库的意义。您要么信任 CA,要么不信任。
标签: java ldap jndi connection-pooling