java - Spring Boot 2 - 连接两个 LDAP 模板
问题描述
我需要在我的 Spring Boot 2 应用程序中配置多个 LDAP 数据源/LdapTemplates。第一个 LdapTemplate 将用于大部分工作,而第二个将用于偶尔一次的数据子集(位于其他地方)。
我已经阅读了有关这样做的 StackOverflow 问题,但它们似乎适用于 Spring Boot
1。spring ldap 存储库项目可以访问两个不同的 ldap 目录吗?
使用 Spring LDAP Repository 的多个 LDAP 存储库
据我所知,无论如何都必须完成大部分配置/设置,即使对于一个 LDAP 数据源,早在 Spring Boot 1 中。使用 Spring Boot 2,我只需将属性放在我的配置文件中,就像这样
ldap.url=ldap://server.domain.com:389
ldap.base:DC=domain,DC=com
ldap.username:domain\ldap.svc.acct
ldap.password:secret
并像这样在我的存储库中自动装配模板
@Autowired
private final LdapTemplate ldapTemplate;
我可以走了。(见:https ://stackoverflow.com/a/53474188/3669288 )
对于第二个 LDAP 数据源,我是否可以只添加“ldap2”的属性和配置元素并完成(请参阅链接问题)?或者添加此配置是否会导致 Spring Boot 2 的自动配置认为我正在覆盖它,所以现在我丢失了我的第一个 LdapTemplate,这意味着我现在还需要显式配置它?
如果是这样,我需要配置所有内容,还是仅部分配置有效?例如,如果我添加上下文源配置并将其标记为@Primary
(这适用于 LDAP 数据源吗?),我可以跳过将其显式分配给第一个 LdapTemplate 吗?在相关说明中,我是否还需要添加@EnableLdapRepositories
注释,否则 Spring Boot 2 会自动配置该注释?
TLDR:我需要在 Spring Boot 2 中添加以连接第二个 LdapTemplate 的最低配置是什么?
解决方案
这需要我在周末学到的知识,并将其作为我自己问题的答案。我仍然不是这方面的专家,所以我欢迎更有经验的答案或评论。
说明
首先,我仍然不确定是否需要@EnableLdapRepositories
注释。我还没有使用这些功能,所以我不能说它是否重要,或者 Spring Boot 2 是否仍在自动处理这些问题。我怀疑 Spring Boot 2 是,但我不确定。
其次,Spring Boot 的自动配置都发生在任何用户配置之后,例如我的代码配置了第二个 LDAP 数据源。根据上下文源或 LdapTemplate 的存在,自动配置使用几个条件注释来确定它是否运行。
这意味着它看到了我的“第二个”LDAP 上下文源(条件只是存在一个上下文源 bean,不管它的名称是什么或它使用什么属性)并跳过自己创建一个,这意味着我不再拥有它配置了我的主要数据源。
它还将看到我的“第二个”LdapTemplate(同样,条件只是存在一个 LdapTemplate bean,无论它的名称是什么,或者它正在使用什么上下文源或属性)并跳过自己创建一个,所以我不再有我配置的主要数据源的那部分。
不幸的是,这些条件意味着在这种情况下,两者都没有中间(例如,我可以手动配置上下文源,然后允许 LdapTemplate 的自动配置仍然发生)。所以解决方案是让我的配置在自动配置之后运行,或者根本不利用自动配置并自己设置它们。
至于让我的配置在自动配置之后运行:唯一的方法是让我的配置本身成为自动配置,并将其顺序指定为在 Spring 的内置自动配置之后(参见:https ://stackoverflow.com/a/53474188 /3669288)。这不适合我的用例,所以对于我的情况(因为 Spring Boot 的设置对于标准的单源情况确实有意义)我坚持放弃自动配置并自己设置它们。
编码
如我的问题中所链接的,以下两个答案(尽管部分出于其他原因)很好地涵盖了设置两个数据源,但我还将在此处详细说明我的设置。
spring ldap 存储库项目可以访问两个不同的 ldap 目录吗?
使用 Spring LDAP Repository 的多个 LDAP 存储库
首先,需要创建配置类,因为 Spring Boot 2 以前根本不需要。同样,我省略了@EnableLdapRepositories
注释,部分原因是我还没有使用它,部分原因是我认为 Spring Boot 2 会仍然为我覆盖。(注意:所有这些代码都是在 Stack Overflow 答案框中输入的,因为我没有编写此代码的开发环境,因此跳过了导入,并且代码可能无法完美编译和正常运行,尽管我希望它是好的。)
@Configuration
public class LdapConfiguration {
}
二是手动配置主数据源;曾经被自动配置但不再是的那个。这里可以利用 Spring Boot 的一个自动配置,那就是它读取标准spring.ldap.*
属性(到属性对象中),但由于它没有命名,你必须通过它的完全限定来引用它班级名称。这意味着您可以直接跳到为主数据源设置上下文源。这段代码不像实际的自动配置代码那样功能齐全(参见:Spring Code)我标记了这个 LdapTemplate@Primary
因为对于我的使用,这是主要的数据源,所以它是所有其他自动装配调用应该默认的。这也意味着您不需要@Qualifier
你在哪里自动连接这个源(如后面所见)。
@Configuration
public class LdapConfiguration {
@Bean(name="contextSource")
public LdapContextSource ldapContextSource(@Qualifier("spring.ldap-org.springframework.boot.autoconfigure.ldap.LdapProperties") LdapProperties properties) {
LdapContextSource source = new LdapContextSource();
source.setUrls(properties.getUrls());
source.setUserDn(properties.getUsername());
source.setPassword(properties.getPassword());
source.setBaseEnvironmentProperties(Collections.unmodifiableMap(properties.getBaseEnvironment()));
return source;
}
@Bean(name="ldapTemplate")
@Primary
public LdapTemplate ldapTemplate(@Qualifier("contextSource") LdapContextSource source) {
return new LdapTemplate(source);
}
}
第三是手动配置辅助数据源,这是导致所有这一切的开始。对于这一点,您确实需要将属性读取配置到 LdapProperties 对象中。此代码建立在前面的代码之上,因此您可以看到完整的上下文类。
@Configuration
public class LdapConfiguration {
@Bean(name="contextSource")
public LdapContextSource ldapContextSource(@Qualifier("spring.ldap-org.springframework.boot.autoconfigure.ldap.LdapProperties") LdapProperties properties) {
LdapContextSource source = new LdapContextSource();
source.setUrls(properties.getUrls());
source.setUserDn(properties.getUsername());
source.setPassword(properties.getPassword());
source.setBaseEnvironmentProperties(Collections.unmodifiableMap(properties.getBaseEnvironment()));
return source;
}
@Bean(name="ldapTemplate")
@Primary
public LdapTemplate ldapTemplate(@Qualifier("contextSource") LdapContextSource source) {
return new LdapTemplate(source);
}
@Bean(name="ldapProperties2")
@ConfigurationProperties("app.ldap2")
public LdapProperties ldapProperties2() {
return new LdapProperties();
}
@Bean(name="contextSource2")
public LdapContextSource ldapContextSource2(@Qualifier("ldapProperties2") LdapProperties properties) {
LdapContextSource source = new LdapContextSource();
source.setUrls(properties.getUrls());
source.setUserDn(properties.getUsername());
source.setPassword(properties.getPassword());
source.setBaseEnvironmentProperties(Collections.unmodifiableMap(properties.getBaseEnvironment()));
return source;
}
@Bean(name="ldapTemplate2")
public LdapTemplate ldapTemplate2(@Qualifier("contextSource2") LdapContextSource source) {
return new LdapTemplate(source);
}
}
最后,在使用这些 LdapTemplate 的类中,您可以照常自动装配它们。这使用构造函数自动装配而不是字段自动装配使用的其他两个答案。尽管建议使用构造函数自动装配,但两者在技术上都是有效的。
@Component
public class LdapProcessing {
protected LdapTemplate ldapTemplate;
protected LdapTemplate ldapTemplate2;
@Autowired
public LdapProcessing(LdapTemplate ldapTemplate, @Qualifier("ldapTemplate2") LdapTemplate ldapTemplate2) {
this.ldapTemplate = ldapTemplate;
this.ldapTemplate2 = ldapTemplate2;
}
}
TLDR:定义“第二个”LDAP 数据源会停止第一个 LDAP 数据源的自动配置,因此如果使用多个,则必须(几乎完全)手动配置;即使对于第一个 LDAP 数据源,也无法利用 Spring 的自动配置。
推荐阅读
- javascript - 向对象添加另一个键...值对
- r - 条件格式匹配字符串的所有弹性表格单元格
- rstudio - Tab 键不适用于 Rstudio 中的 Rmarkdown 文件
- java - tool.context 中未解析的类
- php - 我没有通过while循环得到预期的结果
- r - 如何根据 R 中的另一个数据框更改列名?
- asp.net - ASP.NET Web API – FileNotFoundException: 无法加载文件或程序集
- c# - Angular7 - 从 API 调用中获取响应
- python - 从两个文件路径之一加载数据的最干净和最pythonic的方法是什么?为什么我不能捕获两个相同的异常?
- javascript - 如何将物品转入