审计

基础

Spring Data 提供了精密的支持,可以透明地跟踪谁创建或更改了实体以及更改发生的时间。要利用此功能,您必须为实体类配备审计元数据,可以通过使用注释或实现接口来定义。此外,必须通过注释配置或 XML 配置启用审计,以注册所需的基础设施组件。有关配置示例,请参阅特定于存储的章节。

仅跟踪创建和修改日期的应用程序不需要让其实体实现 AuditorAware

基于注解的审计元数据

我们提供 @CreatedBy@LastModifiedBy 来捕获创建或修改实体的用户,以及 @CreatedDate@LastModifiedDate 来捕获更改发生的时间。

一个经过审计的实体
class Customer {

  @CreatedBy
  private User user;

  @CreatedDate
  private Instant createdDate;

  // … further properties omitted
}

如您所见,可以根据您要捕获的信息选择性地应用这些注解。指示捕获更改时间的注解可以用于 JDK8 日期和时间类型、longLong 以及传统 Java DateCalendar 类型的属性。

审计元数据不一定需要位于根级实体中,也可以添加到嵌入式实体中(取决于使用的实际存储),如下面的代码片段所示。

嵌入式实体中的审计元数据
class Customer {

  private AuditMetadata auditingMetadata;

  // … further properties omitted
}

class AuditMetadata {

  @CreatedBy
  private User user;

  @CreatedDate
  private Instant createdDate;

}

基于接口的审计元数据

如果您不想使用注解来定义审计元数据,您可以让您的域类实现 Auditable 接口。它为所有审计属性公开 setter 方法。

AuditorAware

如果您使用 @CreatedBy@LastModifiedBy,审计基础设施需要以某种方式了解当前主体。为此,我们提供了一个 AuditorAware<T> SPI 接口,您需要实现该接口来告诉基础设施当前与应用程序交互的用户或系统是谁。泛型类型 T 定义了用 @CreatedBy@LastModifiedBy 注解的属性必须是什么类型。

以下示例展示了使用 Spring Security 的 Authentication 对象实现该接口。

基于 Spring Security 的 AuditorAware 实现
class SpringSecurityAuditorAware implements AuditorAware<User> {

  @Override
  public Optional<User> getCurrentAuditor() {

    return Optional.ofNullable(SecurityContextHolder.getContext())
            .map(SecurityContext::getAuthentication)
            .filter(Authentication::isAuthenticated)
            .map(Authentication::getPrincipal)
            .map(User.class::cast);
  }
}

该实现访问由 Spring Security 提供的 Authentication 对象,并查找您在 UserDetailsService 实现中创建的自定义 UserDetails 实例。我们在此假设您通过 UserDetails 实现公开域用户,但基于找到的 Authentication,您也可以从任何地方查找它。

ReactiveAuditorAware

当使用响应式基础设施时,您可能希望利用上下文信息来提供 @CreatedBy@LastModifiedBy 信息。我们提供了一个 ReactiveAuditorAware<T> SPI 接口,您需要实现该接口来告诉基础设施当前与应用程序交互的用户或系统是谁。泛型类型 T 定义了用 @CreatedBy@LastModifiedBy 注解的属性必须是什么类型。

以下示例展示了使用响应式 Spring Security 的 Authentication 对象实现该接口。

基于 Spring Security 的 ReactiveAuditorAware 实现
class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {

  @Override
  public Mono<User> getCurrentAuditor() {

    return ReactiveSecurityContextHolder.getContext()
                .map(SecurityContext::getAuthentication)
                .filter(Authentication::isAuthenticated)
                .map(Authentication::getPrincipal)
                .map(User.class::cast);
  }
}

该实现访问由 Spring Security 提供的 Authentication 对象,并查找您在 UserDetailsService 实现中创建的自定义 UserDetails 实例。我们在此假设您通过 UserDetails 实现公开域用户,但基于找到的 Authentication,您也可以从任何地方查找它。

还提供了一个方便的基类 AbstractAuditable,您可以扩展它以避免手动实现接口方法。这样做会增加您的域类与 Spring Data 的耦合,这可能是您想要避免的。通常,基于注解的方式定义审计元数据是首选,因为它侵入性更小,更灵活。

通用审计配置

Spring Data JPA 附带一个实体监听器,可用于触发审计信息的捕获。首先,您必须在 orm.xml 文件中注册 AuditingEntityListener 以用于您所有持久化上下文中的所有实体,如下例所示

示例 1. 审计配置 orm.xml
<persistence-unit-metadata>
  <persistence-unit-defaults>
    <entity-listeners>
      <entity-listener class="….data.jpa.domain.support.AuditingEntityListener" />
    </entity-listeners>
  </persistence-unit-defaults>
</persistence-unit-metadata>

您还可以使用 @EntityListeners 注解在每个实体的基础上启用 AuditingEntityListener,如下所示

@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyEntity {

}
审计功能需要 spring-aspects.jar 在类路径上。

orm.xml 适当修改且 spring-aspects.jar 在类路径上后,激活审计功能只需将 Spring Data JPA auditing 命名空间元素添加到您的配置中,如下所示

示例 2. 使用 XML 配置激活审计
<jpa:auditing auditor-aware-ref="yourAuditorAwareBean" />

从 Spring Data JPA 1.5 开始,您可以通过使用 @EnableJpaAuditing 注解注释配置类来启用审计。您仍然必须修改 orm.xml 文件,并且 spring-aspects.jar 必须在类路径上。以下示例展示了如何使用 @EnableJpaAuditing 注解

示例 3. 使用 Java 配置激活审计
@Configuration
@EnableJpaAuditing
class Config {

  @Bean
  public AuditorAware<AuditableUser> auditorProvider() {
    return new AuditorAwareImpl();
  }
}

如果您向 ApplicationContext 公开类型为 AuditorAware 的 bean,则审计基础结构会自动将其拾取并使用它来确定要设置在域类型上的当前用户。如果您在 ApplicationContext 中注册了多个实现,则可以通过显式设置 @EnableJpaAuditingauditorAwareRef 属性来选择要使用的实现。