What is entity auditing in Spring Data (@CreatedDate, @LastModifiedBy, etc.)?

8 minintermediateauditingcreateddateentitylisteners

Quick Answer

Spring Data JPA auditing automatically populates fields like createdDate, lastModifiedDate, createdBy, and lastModifiedBy on an entity whenever it's persisted or updated, without any manual code in the service layer. It requires annotating the relevant fields (@CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy), enabling auditing via @EnableJpaAuditing, adding @EntityListeners(AuditingEntityListener.class) to the entity, and — for the *By fields — providing an AuditorAware bean that supplies the current user identity.

Detailed Answer

Spring Data JPA's auditing support automatically populates common bookkeeping fields — when an entity was created/modified, and by whom — without hand-writing that logic in every service method that saves or updates an entity.

1. Enable auditing on a configuration class:

@Configuration
@EnableJpaAuditing
class JpaConfig {
    @Bean
    AuditorAware<String> auditorProvider() {
        return () -> Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                              .map(Authentication::getName); // current logged-in user, e.g. from Spring Security
    }
}

2. Annotate the entity's audit fields, and add the listener that populates them:

@Entity
@EntityListeners(AuditingEntityListener.class)
class Order {
    @Id @GeneratedValue
    Long id;

    @CreatedDate
    Instant createdDate;

    @LastModifiedDate
    Instant lastModifiedDate;

    @CreatedBy
    String createdBy;

    @LastModifiedBy
    String lastModifiedBy;
}

Once configured, saving a new Order automatically sets createdDate/createdBy (and also lastModifiedDate/lastModifiedBy, since a creation is also technically the first modification); subsequent updates automatically refresh just lastModifiedDate/lastModifiedBycreatedDate/createdBy remain untouched on later updates.

Why this matters in practice: it eliminates a very common source of copy-pasted, easy-to-forget boilerplate (order.setCreatedDate(Instant.now()) scattered across every service method that creates an entity), and — since it's driven by JPA lifecycle callbacks (@PrePersist/@PreUpdate under the hood, via AuditingEntityListener) — it's applied consistently regardless of which code path actually triggers the save, including paths a developer might otherwise forget to update.

A common base-class pattern extracts these four fields into a shared @MappedSuperclass, so every auditable entity just extends it rather than repeating the four annotated fields on every entity class individually.