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 方法在首先将新实体持久化到存储区时发挥作用。请确保您实际使用了存储库的 `save(…)` 方法返回的结果,因为这现在将与您最初提供给该方法的实例不同。

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

支持 Vavr 的 Try Monad

默认情况下,Spring Data 存储库将查询方法执行期间发生的错误作为运行时异常传播。采用更函数式编程风格的 Java 代码的支持者通常会在他们的应用程序中使用 Vavr。我们已经有一段时间支持 Vavr 的集合类型作为存储库返回类型了。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 存储库中的示例

延迟 JPA 存储库初始化

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

从 Spring Data Lovelace 开始,您现在可以将存储库定义为以延迟模式引导,这会自动将 Spring Data 存储库的所有注入点声明为延迟加载。这会导致 Spring Framework 创建代理并延迟实际存储库的初始化,直到与它们的第一次交互为止。换句话说,存储库客户端和这些客户端的客户端可以依次创建,而无需等待 `EntityManagerFactory` 完成其引导。这意味着可以将更高数量的 Spring bean 初始化并行化到 JPA 引导。

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

在这些模式之间切换最简单的方法是将 Spring Boot 属性 `spring.jpa.repositories.bootstrap-mode` 设置为 `lazy` 或 `deferred`。这也确保正确配置 `EntityManagerFactory` 的延迟初始化。此外,请务必查看添加到参考文档的新部分。

一个例子

我们准备了一个示例,以在一个相当极端的例子中展示这种优化的效果,该例子包含 2,000 个实体、2,000 个存储库和 2,000 个依赖于存储库的 bean。使用延迟模式可以减少大约三分之一(~12 秒)的启动时间。延迟模式甚至比默认模式快了三分之一(比默认模式快 ~22 秒)。

deferred jpa

控制 Spring Data REST 中的 HTTP 方法公开

最后,我们来看一下 Spring Data REST 中一个已经请求了一段时间的特性。在 Spring Data REST 中,关于为哪些公开的资源类型支持哪些 HTTP 方法的决定,默认情况下是由声明的 CRUD 方法驱动的。但是,在某些情况下,单个存储库方法的存在会导致启用多个资源-HTTP-方法组合。例如,在存储库上公开的 `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();

如您所见,配置选项有两种形式:

  • 全局选项(首先显示),允许通过在 `ResourceMapping` 和 `ConfigurableHttpMethods` 上使用 lambda 来控制集合、项目和关联资源的公开。

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

您可以在参考文档的相应章节中了解更多信息。

获取Spring通讯

关注Spring通讯

订阅

领先一步

VMware提供培训和认证,助您快速提升技能。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

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

查看全部