審計

基礎知識

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,審計基礎設施需要以某種方式感知當前的Principal。為此,我們提供了 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 {

}
審計功能要求 classpath 中包含 spring-aspects.jar

在適當地修改 orm.xml 檔案並確保 classpath 中包含 spring-aspects.jar 後,啟用審計功能只需在您的配置中新增 Spring Data JPA 的 auditing 名稱空間元素,如下所示

示例 2. 使用 XML 配置啟用審計
<jpa:auditing auditor-aware-ref="yourAuditorAwareBean" />

從 Spring Data JPA 1.5 版本開始,您可以透過使用 @EnableJpaAuditing 註解來標記配置類以啟用審計。您仍然必須修改 orm.xml 檔案並確保 classpath 中包含 spring-aspects.jar。以下示例展示瞭如何使用 @EnableJpaAuditing 註解

示例 3. 使用 Java 配置啟用審計
@Configuration
@EnableJpaAuditing
class Config {

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

如果您將 AuditorAware 型別的 bean 暴露給 ApplicationContext,審計基礎設施會自動檢測到它,並使用它來確定要在領域型別上設定的當前使用者。如果您在 ApplicationContext 中註冊了多個實現,可以透過顯式設定 @EnableJpaAuditingauditorAwareRef 屬性來選擇要使用哪一個。