池化支持

池化 LDAP 连接有助于减轻为每次 LDAP 交互创建新 LDAP 连接带来的开销。虽然 Java LDAP 池化支持 存在,但其配置选项和功能(如连接验证和池维护)有限。Spring LDAP 提供了对每个 ContextSource 的详细池配置的支持。

池化支持是通过在应用程序上下文配置中的 <ldap:context-source /> 元素中提供一个 <ldap:pooling /> 子元素来提供的。只读和读写 DirContext 对象分别进行池化(如果指定了 anonymous-read-only)。Jakarta Commons-Pool 用于提供底层池实现。

DirContext 验证

池化连接的验证是使用自定义池库而不是 JDK 提供的 LDAP 池化功能的主要动机。验证允许在将池化 DirContext 连接从池中检出、检入池或在池中处于空闲状态时检查它们是否仍然正确连接和配置。

如果配置了连接验证,则通过使用 DefaultDirContextValidator 来验证池化连接。DefaultDirContextValidator 执行 DirContext.search(String, String, SearchControls),其中名称为空,过滤器为 "objectclass=*",并且 SearchControls 设置为仅限制一个结果,其中只有 objectclass 属性和 500 毫秒的超时。如果返回的 NamingEnumeration 包含结果,则 DirContext 通过验证。如果未返回任何结果或抛出异常,则 DirContext 验证失败。默认设置无需任何配置更改即可在大多数 LDAP 服务器上工作,并提供验证 DirContext 的最快方法。如果需要自定义,可以通过使用验证配置属性来实现,如 池配置 中所述。

如果连接抛出被认为是非瞬态的异常,则会自动将其失效。例如,如果 DirContext 实例抛出 javax.naming.CommunicationException,则将其解释为非瞬态错误,并且该实例会自动失效,而无需额外 testOnReturn 操作的开销。被解释为非瞬态的异常是通过使用 PoolingContextSourcenonTransientExceptions 属性来配置的。

池配置

以下属性可在 <ldap:pooling /> 元素上使用,用于配置 DirContext 池

表 1. 池配置属性
属性 默认值 描述

max-active

8

每种类型(只读或读写)的活动连接的最大数量,这些连接可以同时从该池分配。您可以使用非正数表示无限制。

max-total

-1

可以同时从该池分配的所有类型活动连接的总最大数量。您可以使用非正数表示无限制。

max-idle

8

每种类型(只读或读写)的活动连接的最大数量,这些连接可以保持空闲状态,而不会释放额外的连接。您可以使用非正数表示无限制。

min-idle

0

每种类型(只读或读写)的活动连接的最小数量,这些连接可以保持空闲状态,而不会创建额外的连接。您可以使用零(默认值)来不创建任何连接。

max-wait

-1

池在(没有可用连接时)等待连接返回的最大毫秒数,然后再抛出异常。您可以使用非正数表示无限期等待。

when-exhausted

BLOCK

指定池耗尽时的行为。

  • FAIL 选项在池耗尽时抛出 NoSuchElementException

  • BLOCK 选项等待直到有新的对象可用。如果 max-wait 为正,并且在 max-wait 时间到期后没有新的对象可用,则会抛出 NoSuchElementException

  • GROW 选项创建并返回一个新对象(基本上使 max-active 毫无意义)。

test-on-borrow

false

是否在从池中借用对象之前对其进行验证。如果对象验证失败,则将其从池中删除,并尝试借用另一个对象。

test-on-return

false

是否在将对象返回到池之前对其进行验证。

test-while-idle

false

空闲对象逐出器(如果有)是否验证对象。如果对象验证失败,则将其从池中删除。

eviction-run-interval-millis

-1

在空闲对象逐出器线程的每次运行之间休眠的毫秒数。当为非正数时,不会运行空闲对象逐出器线程。

tests-per-eviction-run

3

在空闲对象逐出器线程(如果有)的每次运行期间检查的对象数量。

min-evictable-time-millis

1000 * 60 * 30(30 分钟)

对象在池中保持空闲状态的最小时间量,之后才能由空闲对象逐出器(如果有)进行逐出。

验证查询基础

LdapUtils.emptyName()

验证连接时使用的搜索基础。仅当指定了test-on-borrowtest-on-returntest-while-idle时使用。

验证查询过滤器

objectclass=*

验证连接时使用的搜索过滤器。仅当指定了test-on-borrowtest-on-returntest-while-idle时使用。

验证查询搜索控制引用

null;默认搜索控制设置如上所述。

验证连接时要使用的SearchControls实例的ID。仅当指定了test-on-borrowtest-on-returntest-while-idle时使用。

非瞬态异常

javax.naming.CommunicationException

Exception类的逗号分隔列表。列出的异常在热切失效方面被认为是非瞬态的。如果对池化的DirContext实例的调用抛出任何列出的异常(或其子类),则该对象会自动失效,而无需任何额外的testOnReturn操作。

Pool2 配置

以下属性可在<ldap:pooling2 />元素上使用,用于配置DirContext

表 2. 池配置属性
属性 默认值 描述

max-total

-1

可以同时从该池分配的所有类型活动连接的总最大数量。您可以使用非正数表示无限制。

每个键的最大总数

8

每个键由池分配的对象实例数(已检出或空闲)的限制。当达到限制时,子池将耗尽。负值表示没有限制。

每个键的最大空闲数

8

每种类型(只读或读写)的活动连接的最大数量,这些连接可以保持空闲状态,而无需释放额外的连接。负值表示没有限制。

每个键的最小空闲数

0

每种类型(只读或读写)的活动连接的最小数量,这些连接可以保持空闲状态,而无需创建额外的连接。您可以使用零(默认值)来不创建任何连接。

max-wait

-1

池在(没有可用连接时)等待连接返回的最大毫秒数,然后再抛出异常。您可以使用非正数无限期等待。

耗尽时阻塞

true

是否等到有新的对象可用。如果max-wait为正,则如果在maxWait时间到期后没有新的对象可用,则会抛出NoSuchElementException

创建时测试

false

在借用之前是否验证对象。如果对象验证失败,则借用失败。

test-on-borrow

false

对象在从池中借用之前是否被验证的指示器。如果对象验证失败,则将其从池中删除,并尝试借用另一个对象。

test-on-return

false

对象在返回到池之前是否被验证的指示器。

test-while-idle

false

对象是否由空闲对象逐出器(如果有)验证的指示器。如果对象验证失败,则将其从池中删除。

eviction-run-interval-millis

-1

在空闲对象逐出器线程的每次运行之间休眠的毫秒数。当为非正数时,不会运行空闲对象逐出器线程。

tests-per-eviction-run

3

在空闲对象逐出器线程(如果有)的每次运行期间检查的对象数量。

min-evictable-time-millis

1000 * 60 * 30(30 分钟)

对象在池中保持空闲状态的最小时间量,之后才能由空闲对象逐出器(如果有)进行逐出。

软最小可逐出时间(毫秒)

-1

对象在池中空闲的最短时间,在此时间之后它才有资格被空闲对象逐出器逐出,并附带一个额外条件,即每个键至少有最少数量的对象实例保留在池中。如果将其设置为正值,则此设置将被min-evictable-time-millis覆盖。

逐出策略类

org.apache.commons.pool2.impl.DefaultEvictionPolicy

此池使用的逐出策略实现。池尝试使用线程上下文类加载器加载类。如果失败,池尝试使用加载此类的类加载器加载类。

公平性

false

池公平地为等待借用连接的线程提供服务。true表示等待的线程被服务的方式就像在FIFO队列中等待一样。

JMX启用

true

使用平台MBean服务器为池启用JMX。

JMX名称基础

null

用作分配给JMX启用的池的名称的一部分的JMX名称基础。

JMX名称前缀

pool

用作分配给JMX启用的池的名称的一部分的JMX名称前缀。

后进先出

true

指示池在空闲对象方面是否具有后进先出(LIFO)行为,或者作为先入先出(FIFO)队列。LIFO始终从池中返回最近使用的对象,而FIFO始终返回空闲对象池中最旧的对象

验证查询基础

LdapUtils.emptyPath()

用于验证搜索的基础DN。

验证查询过滤器

objectclass=*

用于验证查询的过滤器。

验证查询搜索控制引用

null;默认搜索控制设置如上所述。

验证连接时要使用的SearchControls实例的ID。仅当指定了test-on-borrowtest-on-returntest-while-idle时使用

非瞬态异常

javax.naming.CommunicationException

Exception类的逗号分隔列表。列出的异常在热切失效方面被认为是非瞬态的。如果对池化的DirContext实例的调用抛出任何列出的异常(或其子类),则该对象会自动失效,而无需任何额外的testOnReturn操作。

配置

配置池需要添加一个嵌套在<ldap:context-source>元素中的<ldap:pooling>元素,如下所示

<beans>
   ...
    <ldap:context-source
        password="secret" url="ldap://127.0.0.1:389" username="cn=Manager">
        <ldap:pooling />
    </ldap:context-source>
   ...
</beans>

在实际情况中,您可能会配置池选项并启用连接验证。前面的示例演示了总体思路。

验证配置

以下示例在将每个DirContext传递给客户端应用程序之前对其进行测试,并测试已在池中空闲的DirContext对象

<beans>
   ...
    <ldap:context-source
        username="cn=Manager" password="secret" url="ldap://127.0.0.1:389" >
        <ldap:pooling
            test-on-borrow="true"
            test-while-idle="true" />
    </ldap:context-source>
   ...
</beans>

已知问题

本节描述了人们使用Spring LDAP时有时会出现的问题。目前,它涵盖以下问题

自定义身份验证

PoolingContextSource假设从ContextSource.getReadOnlyContext()检索到的所有DirContext对象具有相同的环境,同样,从ContextSource.getReadWriteContext()检索到的所有DirContext对象也具有相同的环境。这意味着将配置了AuthenticationSourceLdapContextSource包装在PoolingContextSource中不会按预期工作。池将使用第一个用户的凭据填充,并且,除非需要新连接,否则后续的上下文请求不会为请求线程的AuthenticationSource指定的用户填充。