Pooling Support

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

Pooling LDAP connections helps mitigate the overhead of creating a new LDAP connection for each LDAP interaction. While Java LDAP pooling support exists, it is limited in its configuration options and features, such as connection validation and pool maintenance. Spring LDAP provides support for detailed pool configuration on a per-ContextSource basis.

通过在应用程序上下文配置中为 <ldap:context-source /> 元素提供 <ldap:pooling /> 子元素的方式提供了池化支持。只读和读写 DirContext 对象将被单独池化(如果指定了 anonymous-read-only)。 Jakarta Commons-Pool 用于提供底层池实现。

Pooling support is provided by supplying a <ldap:pooling /> child element to the <ldap:context-source /> element in the application context configuration. Read-only and read-write DirContext objects are pooled separately (if anonymous-read-only is specified). Jakarta Commons-Pool is used to provide the underlying pool implementation.

DirContext Validation

与 JDK 提供的 LDAP 池化功能相比,池化连接验证是使用自定义池化库的主要动机。验证允许检查池化 DirContext 连接,以确保在从池中检出连接、将连接检入池,或者连接处于池空闲状态时,这些连接仍然正确连接和配置。

Validation of pooled connections is the primary motivation for using a custom pooling library versus the JDK-provided LDAP pooling functionality. Validation allows pooled DirContext connections to be checked to ensure that they are still properly connected and configured when checking them out of the pool, checking them into the pool, or while they are idle in the pool.

如果配置了连接验证,则会使用 DefaultDirContextValidator 来验证池连接。 DefaultDirContextValidator 会执行一个 DirContext.search(String, String, SearchControls),其中名称为空、过滤器为 "objectclass=*"、且 SearchControls 被设置为用仅包含 objectclass 特性和 500ms 超时的单个结果作为限制。如果返回的 NamingEnumeration 中有结果,则 DirContext 将通过验证。如果没有返回结果或抛出异常,则 DirContext 将验证失败。对于大多数 LDAP 服务器,默认设置应该不需要进行任何配置更改,并且提供最快的验证 DirContext 的方式。如果你需要自定义,可以使用 Pool Configuration 中描述的验证配置属性。

If connection validation is configured, pooled connections are validated by using DefaultDirContextValidator. DefaultDirContextValidator does a DirContext.search(String, String, SearchControls), with an empty name, a filter of "objectclass=*", and SearchControls set to limit a single result with the only the objectclass attribute and a 500ms timeout. If the returned NamingEnumeration has results, the DirContext passes validation. If no results are returned or an exception is thrown, the DirContext fails validation. The default settings should work with no configuration changes on most LDAP servers and provide the fastest way to validate the DirContext. If you need customization, you can do so by using the validation configuration attributes, described in Pool Configuration.

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

Connections are automatically invalidated if they throw an exception that is considered non-transient. For example, if a DirContext instance throws a javax.naming.CommunicationException, it is interpreted as a non-transient error and the instance is automatically invalidated, without the overhead of an additional testOnReturn operation. The exceptions that are interpreted as non-transient are configured by using the nonTransientExceptions property of the PoolingContextSource.

Pool Configuration

<ldap:pooling /> 元素上提供了以下属性用于 DirContext 池的配置:

The following attributes are available on the <ldap:pooling /> element for configuration of the DirContext pool:

Table 1. Pooling Configuration Attributes
Attribute Default Description

max-active

8

The maximum number of active connections of each type (read-only or read-write) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-total

-1

The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-idle

8

The maximum number of active connections of each type (read-only or read-write) that can remain idle in the pool without extra connections being released. You can use a non-positive number for no limit.

min-idle

0

The minimum number of active connections of each type (read-only or read-write) that can remain idle in the pool without extra connections being created. You can use zero (the default) to create none.

max-wait

-1

The maximum number of milliseconds that the pool waits (when no connections are available) for a connection to be returned before throwing an exception. You can use a non-positive number to wait indefinitely.

when-exhausted

BLOCK

Specifies the behavior when the pool is exhausted.

  • The FAIL option throws NoSuchElementException when the pool is exhausted.

  • The BLOCK option waits until a new object is available. If max-wait is positive and no new object is available after the max-wait time expires, NoSuchElementException is thrown.

  • The GROW option creates and returns a new object (essentially making max-active meaningless).

test-on-borrow

false

Whether objects are validated before being borrowed from the pool. If the object fails to validate, it is dropped from the pool, and an attempt to borrow another is made.

test-on-return

false

Whether objects are validated before being returned to the pool.

test-while-idle

false

Whether objects are validated by the idle object evictor (if any). If an object fails to validate, it is dropped from the pool.

eviction-run-interval-millis

-1

The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread is run.

tests-per-eviction-run

3

The number of objects to examine during each run of the idle object evictor thread (if any).

min-evictable-time-millis

1000 * 60 * 30 (30 minutes)

The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any).

validation-query-base

LdapUtils.emptyName()

The search base to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified.

validation-query-filter

objectclass=*

The search filter to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified.

validation-query-search-controls-ref

null; default search control settings are described above.

The ID of a SearchControls instance to be used when validating connections. Only used if test-on-borrow, test-on-return, or test-while-idle is specified.

non-transient-exceptions

javax.naming.CommunicationException

Comma-separated list of Exception classes. The listed exceptions are considered non-transient with regards to eager invalidation. Should any of the listed exceptions (or subclasses of them) be thrown by a call to a pooled DirContext instance, that object is automatically invalidated without any additional testOnReturn operation.

Pool2 Configuration

<ldap:pooling2 /> 元素上提供了以下属性用于配置 DirContext 池:

The following attributes are available on the <ldap:pooling2 /> element for configuring the DirContext pool:

Table 2. Pooling Configuration Attributes
Attribute Default Description

max-total

-1

The overall maximum number of active connections (for all types) that can be allocated from this pool at the same time. You can use a non-positive number for no limit.

max-total-per-key

8

The limit on the number of object instances allocated by the pool (checked out or idle), per key. When the limit is reached, the sub-pool is exhausted. A negative value indicates no limit.

max-idle-per-key

8

The maximum number of active connections of each type (read-only or read-write) that can remain idle in the pool, without extra connections being released. A negative value indicates no limit.

min-idle-per-key

0

The minimum number of active connections of each type (read-only or read-write) that can remain idle in the pool, without extra connections being created. You can use zero (the default) to create none.

max-wait

-1

The maximum number of milliseconds that the pool waits (when there are no available connections) for a connection to be returned before throwing an exception. You can use a non-positive number to wait indefinitely.

block-when-exhausted

true

Whether to wait until a new object is available. If max-wait is positive, a NoSuchElementException is thrown if no new object is available after the maxWait time expires.

test-on-create

false

Whether objects are validated before borrowing. If the object fails to validate, then borrowing fails.

test-on-borrow

false

The indicator for whether objects are validated before being borrowed from the pool. If the object fails to validate, it is dropped from the pool, and an attempt to borrow another is made.

test-on-return

false

The indicator for whether objects are validated before being returned to the pool.

test-while-idle

false

The indicator for whether objects are validated by the idle object evictor (if any). If an object fails to validate, it is dropped from the pool.

eviction-run-interval-millis

-1

The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread is run.

tests-per-eviction-run

3

The number of objects to examine during each run of the idle object evictor thread (if any).

min-evictable-time-millis

1000 * 60 * 30 (30 minutes)

The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor (if any).

soft-min-evictable-time-millis

-1

The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle object evictor, with the extra condition that at least the minimum number of object instances per key remain in the pool. This setting is overridden by min-evictable-time-millis if it is set to a positive value.

eviction-policy-class

org.apache.commons.pool2.impl.DefaultEvictionPolicy

The eviction policy implementation that is used by this pool. The pool tries to load the class by using the thread context class loader. If that fails, the pool tries to load the class by using the class loader that loaded this class.

fairness

false

The pool serves threads that are waiting to borrow connections fairly. true means that waiting threads are served as if waiting in a FIFO queue.

jmx-enable

true

JMX is enabled with the platform MBean server for the pool.

jmx-name-base

null

The JMX name base that is used as part of the name assigned to JMX enabled pools.

jmx-name-prefix

pool

The JMX name prefix that is used as part of the name assigned to JMX enabled pools.

lifo

true

The indicator for whether the pool has LIFO (last in, first out) behavior with respect to idle objects or as a FIFO (first in, first out) queue. LIFO always returns the most recently used object from the pool, while FIFO always returns the oldest object in the idle object pool

validation-query-base

LdapUtils.emptyPath()

The base DN to use for validation searches.

validation-query-filter

objectclass=*

The filter to use for validation queries.

validation-query-search-controls-ref

null; default search control settings are described above.

The ID of a SearchControls instance to be used when validating connections. Used only if test-on-borrow, test-on-return, or test-while-idle is specified

non-transient-exceptions

javax.naming.CommunicationException

Comma-separated list of Exception classes. The listed exceptions are considered non-transient with regards to eager invalidation. Should any of the listed exceptions (or subclasses of them) be thrown by a call to a pooled DirContext instance, that object is automatically invalidated without any additional testOnReturn operation.

Configuration

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

Configuring pooling requires adding an <ldap:pooling> element nested in the <ldap:context-source> element, as follows:

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

在实际情况中,您可能需要配置池选项并启用连接验证。之前的示例展示了这个基本思想。

In a real-world situation, you would probably configure the pool options and enable connection validation. The preceding example demonstrates the general idea.

Validation Configuration

以下示例在将 DirContext 传递给客户端应用程序之前对它进行测试,并对已处于池中处于空闲状态的 DirContext 对象进行测试:

The following example tests each DirContext before it is passed to the client application and tests DirContext objects that have been sitting idle in the pool:

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

Known Issues

本节介绍在人们使用 Spring LDAP 时有时会遇到的问题。目前,它涵盖以下问题:

This section describes issues that sometimes arise when people use Spring LDAP. At present, it covers the following issues:

Custom Authentication

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

The PoolingContextSource assumes that all DirContext objects retrieved from ContextSource.getReadOnlyContext() have the same environment and, likewise, that all DirContext objects retrieved from ContextSource.getReadWriteContext() have the same environment. This means that wrapping an LdapContextSource configured with an AuthenticationSource in a PoolingContextSource does not function as expected. The pool would be populated by using the credentials of the first user, and, unless new connections were needed, subsequent context requests would not be filled for the user specified by the AuthenticationSource for the requesting thread.