我有一个使用Spring LDAP 1.3.1的应用程序。它在启动时在Spring上下文中创建LdapTemplate,并将其传递给我的应用程序。我连接的LDAP字符串实际上是一个VIP设备,后面有多个Active Directory服务器。
该应用程序用于创建组层次结构,并在几个步骤中执行此操作。首先,它创建任何新组,然后删除任何已删除的组,然后更新和更改组,最后更新任何新组或已移动组的父组。
在最后一步中,为了进行移动,我必须查找该组,然后查找它的父级,最后更新父级的成员列表以删除该子组。
以下是问题的起点。每隔一段时间,但不是每次,我都有一个添加了组的运行,但是当代码尝试设置父代时,它会失败,因为新组还没有。我相信正在发生的事情是Spring LDAP正在重新连接每次调用,因为我正在通过VIP并且AD服务器是循环的,我认为新添加的组没有复制,所以选择组返回null并且我的父更新失败。基本上我认为我遇到了AD复制的竞争状态。
所以,很长的解释简短:Spring LDAP 1.3.1,特别是LdapTemplate
,每次都会创建一个新的连接,还是我误解它是如何工作的?有没有办法让它使用池化连接,可以通过配置LdapTemaplate
或设置com.sun.jndi.ldap.connect.pool
?如果我在整个应用程序运行时只使用了一个连接,它应该解决复制问题(如果这就是发生的问题),因为我会被困在一个AD服务器上而不会反弹。
答案 0 :(得分:3)
对于可能偶然发现这篇文章的所有未来开发者,这就是我解决问题的方法......
在Spring LDAP 1.3.2中,SingleContextSource没有一个带ContextSource的构造函数,而只有一个带DirContext的构造函数。我没有看到任何方法从我的LdapContextSource获得一个DirContext
,因此我无法使用ig0774的建议。
但是,在阅读了Oracle文档之后,我发现它已经内置了1.4.1非常简单pooling mechanism。进一步阅读LdapContextSource
的Spring API文档,表明它能够通过调用setPooled(boolean)来启用此池化机制。这基本上使得对连接上的close()
的调用不会真正关闭连接,而是将其返回到“池”。由于我的应用程序是一个大的线性线程,并且在给定时间只打开一个“连接”,这具有使其简单地使用相同连接的净效果,从而绕过我看到的问题我的更新工作更快比复制。打开内置池后,我的错误似乎停止了。
请注意,这不是实现LDAP池方案的好方法。正如JavaDoc所说,这种内置的池化机制存在许多缺陷。如果您需要池化,那么使用Spring LDAP的PoolingContextSource会更好。然而,在我的情况下,我想要一个“池”的反面,所以在这方面似乎对我有用。
另一个选择是简单地不使用VIP,而是直接连接到单个Active Directory服务器,但后来我失去了故障转移功能。
答案 1 :(得分:1)
你可能是对的,因为LdapTemplate
似乎在每次操作后都会关闭连接。解决问题的一种方法是切换Spring配置,以便使用SingleContextSource
作为提供给contextSource
的当前LdapTemplate
的包装器。根据您的配置,这可能如下所示:
<beans>
<bean id="contextSource"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://localhost:389" />
<property name="base" value="dc=fabrikam,dc=com" />
<property name="userName" value="cn=superuser,dc=fabrikam,dc=com" />
<property name="password" value="secret" />
</bean>
<bean id="contextSourceWrapper"
class="org.springframework.ldap.core.support.SingleContextSource">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapTemplate"
class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSourceWrapper" />
</bean>
</beans>