Spring Boot 2 - 连接两个 LDAP 模板

问题描述

我需要在我的 Spring Boot 2 应用程序中配置多个 LDAP 数据源/LdapTemplates。第一个 LdapTemplate 将用于大部分工作,而第二个将用于一次性数据子集(位于其他地方)。

我已经阅读了有关这样做的这些 StackOverflow 问题,但它们似乎是针对 Spring Boot 1 的。
Can a spring ldap repository project access two different ldap directories?
Multiple LDAP repositories with Spring LDAP Repository

据我所知,大部分配置/设置无论如何都必须完成,即使只有一个 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 的设置对于标准的单源情况确实有意义)我坚持放弃自动配置并自己设置它们。

代码

设置两个数据源在以下两个答案中得到了很好的介绍(尽管部分出于其他原因),如我的问题中所链接,但我也会在这里详细介绍我的设置。
Can a spring ldap repository project access two different ldap directories?
Multiple LDAP repositories with Spring LDAP Repository

首先,需要创建配置类,因为之前 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 的自动配置。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...