简介

概览

Spring LDAP 旨在简化 Java 中的 LDAP 编程。该库提供的一些特性包括:

  • 对 LDAP 编程进行类似 JdbcTemplate 风格的模板简化。

  • 类似 JPA 或 Hibernate 的基于注解的对象与目录映射。

  • Spring Data repository 支持,包括对 QueryDSL 的支持。

  • 用于简化构建 LDAP 查询和辨别名(Distinguished Names)的工具。

  • 正确的 LDAP 连接池。

  • 客户端 LDAP 补偿事务支持。

传统 Java LDAP 与 LdapClient 的比较

考虑一个方法,它应该在某个存储中搜索所有人员并以列表形式返回他们的姓名。使用 JDBC,我们将创建一个连接并使用一个语句运行一个查询。然后,我们将遍历结果集并检索我们想要的,将其添加到列表中。

使用 JNDI 操作 LDAP 数据库时,我们将创建一个上下文并使用一个搜索过滤器执行一次搜索。然后,我们将遍历生成的命名枚举,检索我们想要的属性,并将其添加到列表中。

在 Java LDAP 中实现此人员姓名搜索方法的传统方式如下所示。请注意标记为粗体的代码 - 这是实际执行与方法业务目的相关的任务的代码。其余的是样板代码(plumbing)。

public class TraditionalPersonRepoImpl implements PersonRepo {
   public List<String> getAllPersonNames() {
      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
      env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com");

      DirContext ctx;
      try {
         ctx = new InitialDirContext(env);
      } catch (NamingException e) {
         throw new RuntimeException(e);
      }

      List<String> list = new LinkedList<String>();
      NamingEnumeration results = null;
      try {
         SearchControls controls = new SearchControls();
         controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
         results = ctx.search("", "(objectclass=person)", controls);

         while (results.hasMore()) {
            SearchResult searchResult = (SearchResult) results.next();
            Attributes attributes = searchResult.getAttributes();
            Attribute attr = attributes.get("cn");
            String cn = attr.get().toString();
            list.add(cn);
         }
      } catch (NameNotFoundException e) {
         // The base context was not found.
         // Just clean up and exit.
      } catch (NamingException e) {
         throw new RuntimeException(e);
      } finally {
         if (results != null) {
            try {
               results.close();
            } catch (Exception e) {
               // Never mind this.
            }
         }
         if (ctx != null) {
            try {
               ctx.close();
            } catch (Exception e) {
               // Never mind this.
            }
         }
      }
      return list;
   }
}

通过使用 Spring LDAP 的 AttributesMapperLdapClient 类,我们可以使用以下代码获得完全相同的功能:

import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;

   public void setLdapClient(LdapClient ldapClient) {
      this.ldapClient = ldapClient;
   }

   public List<String> getAllPersonNames() {
      return ldapClient.search().query(
            query().where("objectclass").is("person")
         ).toObject((Attributes attrs) ->
            attrs.get("cn").get().toString();
         );
   }
}

与传统示例相比,样板代码量显著减少。LdapClient 搜索方法确保创建了 DirContext 实例,执行搜索,使用给定的 AttributesMapper 将属性映射为字符串,在内部列表中收集这些字符串,最后返回该列表。它还确保 NamingEnumerationDirContext 被正确关闭,并处理可能发生的任何异常。

当然,作为 Spring Framework 的一个子项目,我们使用 Spring 来配置我们的应用程序,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:ldap="http://www.springframework.org/schema/ldap"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/ldap https://www.springframework.org/schema/ldap/spring-ldap.xsd">

   <ldap:context-source
          url="ldap://localhost:389"
          base="dc=example,dc=com"
          username="cn=Manager"
          password="secret" />

   <bean id="ldapClient" class="org.springframework.ldap.core.LdapClient" factory-method="create">
        <constructor-arg ref="contextSource" />
    </bean>

   <bean id="personRepo" class="com.example.repo.PersonRepoImpl">
      <property name="ldapClient" ref="ldapClient" />
   </bean>
</beans>
要使用自定义 XML 命名空间配置 Spring LDAP 组件,您需要在 XML 声明中包含对该命名空间的引用,如前面的示例所示。

2.2 版本的新特性

有关 2.2 的完整详细信息,请参阅 2.2.0.RC1 的变更日志。Spring LDAP 2.2 的亮点如下:

  • #415:添加了对 Spring 5 的支持

  • #399:嵌入式 UnboundID LDAP 服务器支持

  • #410:添加了 Commons Pool 2 支持的文档

2.1 版本的新特性

有关 2.1 的完整详细信息,请参阅 2.1.0.RC12.1.0 的变更日志。Spring LDAP 2.1 的亮点如下。

  • #390:添加了 Spring Data Hopper 支持

  • #351:添加了对 commons-pool2 的支持

  • #370:在 XML 命名空间中添加了对属性占位符的支持

  • #392:添加了文档测试支持

  • #401:切换到 assertj

  • 从 JIRA 迁移到 GitHub Issues

  • 添加了 Gitter 聊天

2.0 版本的新特性

虽然 Spring LDAP 2.0 版本对 API 进行了相当重要的现代化改进,但我们已尽最大努力确保向后兼容性。使用 Spring LDAP 1.3.x 的代码,除少数例外,在使用 2.0 库时无需修改即可编译和运行。

例外情况是少数已移至新包的类,这是为了实现一些重要的重构。这些被移动的类通常不是预期公共 API 的一部分,迁移过程应该是平滑的。如果在升级后找不到 Spring LDAP 类,您应该在 IDE 中组织导入。

不过,您应该会遇到一些弃用警告,并且还有许多其他的 API 改进。为了充分利用 2.0 版本,建议您放弃弃用的类和方法,迁移到新的、改进的 API 工具。

以下列表简要描述了 Spring LDAP 2.0 中最重要的变化:

  • Spring LDAP 现在需要 Java 6。Spring 2.0 及更高版本仍然受支持。

  • 核心 API 已更新,支持 Java 5+ 的特性,例如泛型和可变参数。因此,整个 spring-ldap-tiger 模块已被弃用,我们鼓励您迁移到使用核心 Spring LDAP 类。核心接口的参数化会在现有代码上引起大量编译警告,我们鼓励您采取适当措施消除这些警告。

  • ODM(对象-目录映射)功能已移至核心模块,LdapOperationsLdapTemplate 中新增了一些方法,使用这种自动转换来处理带有 ODM 注解的类。有关更多信息,请参阅对象-目录映射 (ODM)

  • 现在(终于)提供了自定义 XML 命名空间,以简化 Spring LDAP 的配置。有关更多信息,请参阅[配置]

  • Spring LDAP 现在提供对 Spring Data Repository 和 QueryDSL 的支持。有关更多信息,请参阅Spring LDAP 存储库

  • DirContextAdapter 和 ODM 中,现在正确处理了作为属性值的 Name 实例,特别是关于辨别名相等性。有关更多信息,请参阅DirContextAdapter 和属性值作为辨别名 以及 ODM 和属性值作为辨别名

  • DistinguishedName 和相关类已被弃用,取而代之的是标准的 Java LdapName。有关在使用 LdapName 对象时该库如何提供帮助的信息,请参阅动态构建辨别名

  • 添加了 Fluent LDAP 查询构建支持。这使得在 Spring LDAP 中处理 LDAP 搜索时编程体验更加愉快。有关 LDAP 查询构建器支持的更多信息,请参阅构建 LDAP 查询高级 LDAP 查询

  • LdapTemplate 中旧的 authenticate 方法已被弃用,取而代之的是几个新的 authenticate 方法,这些方法使用 LdapQuery 对象,并在认证失败时抛出异常,使用户更容易查明认证尝试失败的原因。

  • 已对示例进行了完善和更新,以便利用 2.0 中的特性。我们付出了相当大的努力来提供一个有用的LDAP 用户管理应用程序示例。

打包概览

至少,使用 Spring LDAP 需要以下依赖项:

  • spring-ldap-core:Spring LDAP 库

  • spring-core:框架内部使用的各种工具类

  • spring-beans:用于操作 Java bean 的接口和类

  • slf4j:一个简单的日志门面,内部使用

除了必需的依赖项外,某些功能还需要以下可选依赖项:

  • spring-data-ldap:用于存储库支持等的基础设施

  • spring-context:如果您的应用程序使用 Spring Application Context 进行装配,则需要此依赖项。spring-context 增加了应用程序对象使用一致 API 获取资源的能力。如果您计划使用 BaseLdapPathBeanPostProcessor,则绝对需要它。

  • spring-tx:如果您计划使用客户端补偿事务支持,则需要此依赖项。

  • spring-jdbc:如果您计划使用客户端补偿事务支持,则需要此依赖项。

  • commons-pool:如果您计划使用连接池功能,则需要此依赖项。

  • spring-batch:如果您计划将 LDIF 解析功能与 Spring Batch 一起使用,则需要此依赖项。

spring-data-ldap 会传递性地添加 spring-repository.xsd,而 spring-ldap.xsd 使用它。因此,即使不使用 Spring Data 的特性集,Spring LDAP 的 XML 配置支持也需要此依赖项。

入门

示例提供了一些关于如何在常见用例中使用 Spring LDAP 的有用示例。

支持

如果您有问题,请在 Stack Overflow 上使用 spring-ldap 标签提问。项目网页是 spring.io/spring-ldap/

致谢

Spring LDAP 项目启动时的初步工作由 Jayway 赞助。该项目目前的维护由 Pivotal 提供资金,Pivotal 后期已被 VMware 收购。

感谢 Structure101 提供了开源许可,这对于检查项目结构非常有用。