如何在没有 DAO 的情况下使用 Spring LDAP 连接到多个 url?
Posted
技术标签:
【中文标题】如何在没有 DAO 的情况下使用 Spring LDAP 连接到多个 url?【英文标题】:How to use Spring LDAP to connect to multiple urls without DAOs? 【发布时间】:2014-09-01 01:25:49 【问题描述】:目前我有一个LDAP管理系统,使用Spring LDAP连接LDAP服务器并进行管理;但是,如果我想更改为不同的服务器,我必须关闭系统,更改配置设置,然后重新启动它。如果我可以简单地有一个允许我在不同服务器之间交换的下拉菜单,那会简单得多。
因此,我正在研究动态设置上下文源的可能性。我找到了Incorrect injection between beans,那里的答案看起来像是我希望能够完成的事情。但是,我的系统没有使用 DAO,而是使用 LdapRepository 来管理用户。
我的问题是:如何更改 Spring 使用的 ContextSource 以在运行时与 LdapRepository 类进行交互,而不是在 xml 文件中设置,同时尽可能保持我当前的项目结构?
我不想将所有东西都转换为使用 DAO,而是让这样的功能与现有代码一起工作。
编辑:还应该提到我也让 Spring 引导存储库的实现。
【问题讨论】:
您的潜在服务器列表是静态的,还是您希望能够动态添加一个新的? @SergeBallesta 它们都是静态的。目前我已经在 LdapTemplate 中启用了通过自动装配进行切换,但是我希望这是会话本地的(所以一个人交换到另一台服务器不会导致每个人都切换)。 在会话中限定您在LdapTemplate
中自动装配的 bean 是否足够?
@Serge 不幸的是,没有。我不是 100% 确定如何实现 LDAPTemplate 和 LDAPRepository 类之间的交互。据我所知,它们都引用同一个 LDAP 模板,而我希望该连接是本地会话,因此我可以执行 session.setLdapTemplate(currentLdapTemplate);
之类的操作,以便在有人切换服务器时创建一个新的 LdapTemplate。
【参考方案1】:
我发现 SO 上的其他 post(与您的问题没有直接关系)显示了如何在会话中限定 LDAPTemplate
。
在不了解您的更多来源的情况下,我无法确定此解决方案是否适合您,但我认为值得一试。
您应该在会话中声明您的 LDAPTemplate 范围:
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"
p:contextSource_ref="contextSource" scope="session">
<aop:scope-proxy/>
</bean>
您应该尝试将其作为 LDAPOperation 注入到您的 LDAPRepository 类中,以允许 Spring AOP 使用 JDK 代理。如果不行,你应该通过<aop:scope-proxy proxy-target-class="true"/>
配置Spring AOP使用cglib
在您要更改ContextSource
的地方,注入LDAPTemplate
。如果您可以使用 JDK 代理,请将其作为 LDAPOperation
注入以获取作用域代理。您应该能够通过 Spring AOP 代理实现的Advised
interface 获得正确的LDAPTemplate
:
LDAPOperation ldapOperation;
...
LDAPTemplate ldapTemplate = (LDAPTemplate) ((Advised)ldapOperation)
.getTargetSource().getTarget();
ldapTemplate.setContextSource(newContextSource);
这里是访问 Spring AOP 代理目标的参考:来自 Tech Per 的 How To Acess Target Object Behind a Spring Proxy
【讨论】:
所有 LdapRepositories 默认使用相同的LdapTemplate
。在调用之前显式设置ContextSource
在多线程环境中会产生未定义的结果。
@marthursson 这就是我建议每个 Http 会话使用一个 LdapTemplate 的原因。【参考方案2】:
这是一种极端情况。该库实际上不是为此而设计的,但我认为实现您想要做的最简单的方法是实现一个自定义委托ContextSource
,它保留对您希望能够的所有不同实际 ContextSources 的引用使用,例如:
public class SessionBasedDelegatingContextSource implements ContextSource
private Map<String, ContextSource> contextSources;
@Required
public void setContextSources(Map<String, ContextSource> contextSources)
this.contextSources = new HashMap<>(contextSources);
protected final ContextSource getSessionContextSource()
String id = (String) RequestContextHolder.currentRequestAttributes()
.getAttribute("currentContextSource", SCOPE_SESSION);
if(id == null)
throw new IllegalStateException("No Ldap target selected");
ContextSource contextSource = contextSources.get(id);
if(contextSource == null)
throw new IllegalArgumentException("No Ldap target selected");
return contextSource;
@Override
public DirContext getReadOnlyContext()
getSessionContextSource().getReadOnlyContext();
@Override
public DirContext getReadWriteContext()
getSessionContextSource().getReadWriteContext();
@Override
public DirContext getContext(String principal, String credentials)
getSessionContextSource().getContext(principal, credentials);
现在,如果您注册一个RequestContextFilter,声明所有不同的 ContextSource,将它们注入SessionBasedDelegatingContextSource
,并将其用作您的存储库的 ContextSource(即您定义的 LdapTemplate 使用的 ContextSource),您只需要要做的是在会话中放置一个适当的 ContextSource 标识符,你应该没问题。
【讨论】:
这几乎正是我最终所做的。谢谢!以上是关于如何在没有 DAO 的情况下使用 Spring LDAP 连接到多个 url?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot下如何自定义Repository中的DAO方法