Spring Data Lovelace 有哪些新特性?

工程 | Oliver Drotbohm | 2018年9月27日 | ...

Spring Data Lovelace 上周刚刚发布了通用版本,是时候快速浏览一下我们添加的新特性了。这个版本包含了很多功能。在这篇博文中,我将介绍一些更通用的特性。关于特定存储的高级特性,将在以下博文中介绍:

阅读完这些了吗?好的,那我们来开始介绍更通用的部分。

改进的不可变类型对象映射

在 Spring Data Lovelace 中,我们借此机会改进了我们用于大多数 NoSQL 模块的对象映射功能。我们一直支持不可变实体,只有一个微小的方面除外:在数据库交互期间需要更改的值,例如自动生成的标识符或乐观锁定版本属性,过去总是在内部被修改。在最新版本中,这一点已经改变。

为了支持这些属性,现在需要您提供一个 wither 方法(遵循 with…(…) 命名约定),或者——在 Kotlin 世界中——公开一个专用的 copy(…) 方法,该方法接受所有属性作为参数。以下示例使用了 withId 方法:

class Person {

  private final Long id;
  private final String firstname, lastname;

  static Person of(String firstname, String lastname) {
    return new Person(null, firstname, lastname);
  }

  private Person(Long id, String firstname, String lastname) {
    // Assign parameters to fields
  }

  Person withId(Long id) {
    return new Person(id, this.firstname, this.lastame);
  }

  // …
}

使用 Lombok,我们可以像下面这样实现:

@Value(staticConstructor = "of")
class Person {

  @Wither Long id;
  String firstname, lastname;

  // …
}

声明的构造函数在从数据库读取 Person 实例时使用。标识符属性的 wither 方法在首次将新实体持久化到存储时起作用。请确保您实际使用了 repository 的 save(…) 方法返回的结果,因为这现在将是与您首次传递给该方法的实例不同的一个新实例。

我们利用这方面的工作改进了一些存储实现中实际对象转换的性能,避免在使用不可变类型时进行一些不必要的属性迭代。有关更多详细信息,请参阅 参考文档中新添加的章节

支持 Vavr 的 Try Monad

默认情况下,Spring Data repository 会将查询方法执行期间发生的错误传播为运行时异常。更倾向于函数式风格编写 Java 代码的开发者通常会在其应用中使用 Vavr。我们早已支持 Vavr 的集合类型作为 repository 的返回类型。Spring Data Lovelace 现在增加了对 Try monad 的支持,这样查询方法执行中发生的错误将返回 Failure 实例,而不是抛出异常。

interface PersonRepository extends Repository<Person, Long> {

  Try<Option<Person>> findByLastnameContaining(String lastname);
}

如果找到多个匹配给定条件的 lastname 的人,该方法将失败。使用 Try 作为返回类型,客户端组件现在可以通过如下方式从这种异常情况中恢复:

repository.findByLastnameContaining("e")
  .recover(it -> Match(it).of(
    Case(instanceOf(IncorrectResultSizeDataAccessException.class), Optional.empty())
));

虽然在这个精心构造的小例子中这可能看起来有点复杂,但这是一种非常强大的机制,可以在可能抛出异常的代码上继续对潜在可用结果进行映射。请注意,当将此功能与事务性存储结合使用时,您必须自己管理事务回滚,因为异常实际上不再抛出,并且不会触发带有 @Transaction 注解方法的事务回滚。对此的支持正在开发中。请务必关注 Spring Framework 中的 这个工单,或者甚至为它投一票。

要查看 Vavr 支持的实际应用,请查阅我们标准的 Spring Data Examples repository 中的示例

延迟的 JPA Repository 初始化

启动一个 Spring Data JPA 应用需要引导一个 EntityManagerFactory。这通常会占用应用程序总启动时间的相当一部分。为了解决这个问题,Spring Framework 已经引入了在后台线程中引导 EntityManagerFactory 的能力,从而让其他 bean 并行初始化。不幸的是,Spring Data repository 通常至少对某种 Spring bean 有传递依赖。它们的初始化反过来又会与工厂进行交互,这——如果不采取进一步措施——会导致这些其他组件的初始化被阻塞。这显著限制了该新功能的效果。

从 Spring Data Lovelace 开始,您现在可以定义以 lazy 模式引导 repository,这将自动将 Spring Data repository 的所有注入点声明为 lazy。这使得 Spring Framework 创建代理并延迟实际的 repository 初始化,直到第一次与它们交互。换句话说,repository 客户端以及这些客户端的客户端可以依次创建,而无需等待 EntityManagerFactory 完成其引导。这意味着可以与 JPA 引导并行进行显著更多的 Spring bean 初始化。

初始化的延迟也会导致任何类型的验证被延迟,直到(例如)实际使用 repository 的代码路径被命中的第一个请求。如果您仍然希望确保在应用程序开始接收请求之前完全初始化 repository,请使用 deferred 引导模式。此模式的工作方式与 lazy 模式相同,不同之处在于,当容器完成引导后,它会显式触发 ApplicationContext 中所有 repository 的初始化。

在这些模式之间切换的最简单方法是将 Spring Boot 属性 spring.jpa.repositories.bootstrap-mode 设置为 lazydeferred。这还确保 EntityManagerFactory 的 lazy 初始化得到正确配置。此外,请务必查阅 参考文档中新添加的章节

一个示例

我们准备了一个示例来展示这种优化在极端情况下的效果,该示例包含 2000 个实体、2000 个 repository 和 2000 个依赖于这些 repository 的 bean。使用 deferred 模式可以缩短约三分之一(约 12 秒)的启动时间。而 lazy 模式甚至可以再缩短三分之一(比默认模式快约 22 秒)。

deferred jpa

控制 Spring Data REST 中的 HTTP 方法暴露

最后,我们来看看 Spring Data REST 中一个被请求了相当长时间的功能。在 Spring Data REST 中,默认情况下,暴露的资源类型支持哪些 HTTP 方法,是根据声明的 CRUD 方法来决定的。然而,在某些情况下,单个 repository 方法的存在会导致多种资源-HTTP-方法组合被启用。例如,repository 上暴露的 save(…) 方法会导致集合资源支持 POST,同时项目资源的更新**和**创建都支持 PUT

Spring Data Lovelace 有一个新的 ExposureConfiguration(可以从 RepositoryRestConfiguration 获取),它允许对哪些方法应该被暴露进行细粒度控制:

ExposureConfiguration config = restConfiguration.getExposureConfiguration();

config.withItemExposure((metadata, httpMethods)
  -> httpMethods.disable(HttpMethod.PATCH));
config.forDomainType(User.class).disablePutForCreation();

如您所见,配置选项有两种类型:

  • 一种是全局的(首先展示),通过使用 lambda over ResourceMappingConfigurableHttpMethods 来控制集合、项目和关联资源的暴露。

  • 一种是类型特定的,如下所示。一些设置细节,例如禁用(默认启用的)使用 PUT 请求创建实体的能力,都可以通过显式的配置方法来支持。

您可以在参考文档的相应章节中找到更多相关信息。

订阅 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

超越他人

VMware 提供培训和认证,助您加速前进。

了解更多

获取支持

Tanzu Spring 通过一份简单的订阅,为 OpenJDK™、Spring 和 Apache Tomcat® 提供支持和二进制文件。

了解更多

即将举办的活动

查看 Spring 社区所有即将举办的活动。

查看全部