【问题标题】:JNDI LDAP Pooled ConnectionsJNDI LDAP 池连接
【发布时间】:2019-12-16 01:58:02
【问题描述】:

我的 JNDI 连接池似乎没有按预期工作。当我运行我的测试时,我看到每次都会创建新的连接。连接成功(因为我可以很好地查询 Active Directory),但它们并没有像我期望的那样进行池化。以下是关于我的设置的一些重要说明:

  1. 连接正在通过 SSL(即 ldaps)

  2. 使用自定义套接字工厂

  3. 对 AD 的身份验证通过“简单”身份验证完成

  4. 使用默认池配置值(目前)

以下是相关代码:

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


【解决方案1】:

根据https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html 的“什么得到池化”部分,它可能是禁用池化的自定义套接字工厂:

有几个环境属性会自动 取消 Context 实例使用池连接的资格。一个 如果上下文实例有它的,则不能使用池连接 “java.naming.ldap.factory.socket”属性设置为自定义套接字 工厂类 (...)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多