首页 > 解决方案 > 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 的最低配置是什么?

标签: javaspringspring-bootspring-ldap

解决方案


这需要我在周末学到的知识,并将其作为我自己问题的答案。我仍然不是这方面的专家,所以我欢迎更有经验的答案或评论。

说明

首先,我仍然不确定是否需要@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 的自动配置。


推荐阅读