[Spring Boot] @EnableJpaAuditing이란?

2026. 10. 23. 01:54·Back-End/Spring

티켓 예매 프로젝트의 공통 패키지를 세팅하면서, 모든 엔티티가 상속할 BaseEntity 에 생성일과 수정일을 자동으로 채우도록 JPA Auditing을 설정하게 되었다.

 

이번 글에서 다룰 개념은 다음과 같다.

@EnableJpaAuditing
@EntityListeners(AuditingEntityListener.class)
@CreatedDate, @LastModifiedDate
JpaAuditingConfig (별도 @Configuration)
@MockitoBean (테스트 쪽 우회 방법)

 

처음 설정할 때 헷갈리는 지점은 @EnableJpaAuditing 을 어디에 붙이느냐다.

 

검색하면 메인 클래스에 바로 붙이는 예제가 많고, 애플리케이션도 그대로 잘 실행된다. 그런데 컨트롤러 슬라이스 테스트인 @WebMvcTest 를 돌리면 컨텍스트 로딩부터 실패한다.

 

핵심은 어노테이션 자체가 아니라, 메인 클래스에 붙은 설정은 모든 슬라이스 테스트에도 함께 따라온다는 점이다.


간단히 정리하면

- @EnableJpaAuditing     : 애플리케이션 전체에 JPA Auditing 기능을 켠다.
- AuditingEntityListener : 엔티티 저장/수정 시점에 Auditing 필드 값을 채운다.
- @CreatedDate 등        : 어떤 필드에 어떤 값을 채울지 표시한다.
- JpaAuditingConfig      : @EnableJpaAuditing 만 담은 별도 설정 클래스다.
- @MockitoBean           : 테스트에서 문제가 되는 빈을 Mock으로 대체한다.
애플리케이션 실행만 고려   → 메인 클래스에 붙여도 동작한다.
@WebMvcTest 를 함께 쓴다   → 별도 @Configuration 으로 분리한다.
@DataJpaTest 에서 필요하다 → @Import(JpaAuditingConfig.class) 로 가져온다.

@EnableJpaAuditing

@EnableJpaAuditing 은 애플리케이션에서 JPA Auditing 기능을 활성화할 때 사용한다.

 

예를 들어 예매, 공연, 회원 엔티티마다 createdAt = LocalDateTime.now() 를 직접 넣는 대신, 저장 시점에 값을 자동으로 채우고 싶을 때 쓴다.

 

어노테이션 내부를 보면 다음과 같이 JpaAuditingRegistrar 를 import 해서 Auditing에 필요한 빈을 등록한다.

@Import(JpaAuditingRegistrar.class)
public @interface EnableJpaAuditing {
    String auditorAwareRef() default "";
    boolean setDates() default true;
    boolean modifyOnCreate() default true;
    String dateTimeProviderRef() default "";
}

 

setDates 는 생성일/수정일을 채울지, modifyOnCreate 는 생성 시점도 수정으로 볼지 정한다. 둘 다 기본값이 true 라서 날짜만 쓴다면 속성을 따로 줄 필요가 없다.

 

auditorAwareRef 는 @CreatedBy, @LastModifiedBy 에 넣을 사용자 정보를 제공하는 AuditorAware 빈이 여러 개일 때, 어떤 빈을 쓸지 지정한다.

 

즉, @EnableJpaAuditing 은 Auditing을 "켜는 스위치"이고, 엔티티에서 값을 채우는 시점은 리스너가 잡아 준다.


@EntityListeners와 @CreatedDate

AuditingEntityListener 는 엔티티가 저장되거나 수정되는 시점에 Auditing 필드를 채울 때 사용한다.

 

Spring Data JPA 공식 문서는 이 리스너를 orm.xml 에 전역으로 등록하거나, 엔티티에 @EntityListeners(AuditingEntityListener.class) 로 등록하는 두 가지 방법을 안내한다.

 

프로젝트에서는 다음과 같이 공통 부모 클래스에 엔티티 단위로 등록했다.

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
}

 

@MappedSuperclass 로 선언했기 때문에 이 클래스를 상속한 엔티티는 두 컬럼과 리스너를 함께 물려받는다. createdAt 은 updatable = false 로 두어 수정 쿼리에서 바뀌지 않게 했다.

 

즉, @EnableJpaAuditing 이 기능을 켜고, @EntityListeners 가 엔티티에 리스너를 연결하고, @CreatedDate 가 채울 필드를 표시한다.

 

중요한 점은 공식 문서가 이 세 가지를 한 세트로 안내한다는 것이다. 필드에 @CreatedDate 만 붙인다고 Auditing이 동작한다고 기대하면 안 된다.


JpaAuditingConfig

JpaAuditingConfig 는 Auditing 설정을 메인 클래스에서 떼어 내, 슬라이스 테스트에 어떤 설정이 올라갈지 제어할 때 사용한다.

 

예를 들어 처음에는 다음과 같이 메인 클래스에 붙이는 방식을 떠올렸다.

@EnableJpaAuditing
@SpringBootApplication
public class TicketRunApplication {
    // ...
}

 

애플리케이션 실행에는 문제가 없다. 하지만 이 상태에서 컨트롤러 하나만 올리는 @WebMvcTest 를 돌리면 컨텍스트 로딩이 실패한다.

 

아직 예매 도메인 컨트롤러가 없어서, 확인용으로 /ping 만 응답하는 최소 컨트롤러를 만들어 실행했다.

@WebMvcTest(PingController.class)
class PingControllerTest {
    // 컨텍스트 로딩 단계에서 실패한다.
}

 

Spring Boot 4.1.1 에서 실행하면 다음과 같은 원인이 찍힌다.

Error creating bean with name 'jpaAuditingHandler':
  Cannot resolve reference to bean 'jpaMappingContext'
Error creating bean with name 'jpaMappingContext':
  JPA metamodel must not be empty

 

Auditing 빈은 JPA 메타모델(엔티티 정보)을 필요로 하는데, @WebMvcTest 는 웹 계층만 올리기 때문에 JPA 관련 구성이 없어서 생기는 에러다.

 

그렇다면 왜 웹 테스트에서 Auditing 빈을 만들려고 했을까?

 

Spring Boot 공식 문서의 User Configuration and Slicing 항목이 이 상황을 설명한다. 메인 클래스는 테스트의 설정 소스이기 때문에, 거기에 붙은 @Enable* 설정은 모든 슬라이스 테스트에서도 활성화된다.

 

문서는 @EnableMongoAuditing 을 예로 들고, 해당 설정을 메인 클래스와 같은 레벨의 별도 @Configuration 클래스로 옮기는 방법을 권장한다.

// @SpringBootApplication 에 두면 JPA 빈이 없는 @WebMvcTest 슬라이스 테스트가 실패하므로 별도 설정으로 분리한다.
@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {
}

 

분리하고 나면 같은 @WebMvcTest 가 통과한다. 같은 문서에 "Test slices exclude @Configuration classes from scanning."이라고 적혀 있듯이, 슬라이스 테스트는 일반 @Configuration 클래스를 스캔하지 않기 때문이다.

 

@WebMvcTest 가 스캔하는 대상은 @Controller, @ControllerAdvice 와 Filter, WebMvcConfigurer, SecurityFilterChain 같은 웹 관련 빈으로 제한된다.

 

즉, 메인 클래스는 피할 수 없이 항상 읽히지만, 별도 설정 클래스는 슬라이스 테스트가 골라서 뺄 수 있다.

 

다만, @DataJpaTest 처럼 Auditing이 필요한 슬라이스 테스트도 있다. @DataJpaTest 도 컴포넌트 스캔을 JPA 리포지토리와 @Entity 로 제한하므로, 공식 문서가 안내하는 대로 @Import 로 가져와야 할 것으로 보인다.

@DataJpaTest
@Import(JpaAuditingConfig.class)
class ReservationRepositoryTest {
    // 필요한 테스트에서만 Auditing 설정을 가져온다.
}

@MockitoBean

추가적으로 메인 클래스에 그대로 두고 테스트 쪽에서 막는 방법도 알아보려고 한다!

 

검색해 보면 이 방식을 해결책으로 소개하는 글도 많아서, 분리 방식과 비교하려고 함께 실행해 보았다.

 

에러 원인이 jpaMappingContext 빈이므로, 테스트에서 이 빈을 Mock으로 대체하면 컨텍스트가 올라간다. Spring Boot 4.0 에서 @MockBean 이 제거되었기 때문에 @MockitoBean 을 쓴다.

@WebMvcTest(PingController.class)
@MockitoBean(types = JpaMetamodelMappingContext.class)
class PingControllerTest {
    // 메인 클래스에 @EnableJpaAuditing 이 있어도 통과한다.
}

 

4.1.1 에서 실행해 보니 이 방식도 통과했다. 다만 이 Mock은 테스트 대상과 상관없는 우회 코드이고, @WebMvcTest 를 새로 만들 때마다 잊지 않고 붙여야 한다.

 

즉, 동작은 하지만 원인(설정 위치)을 그대로 두고 증상만 막는 방법에 가깝다고 생각한다.


정리

세 가지 방식은 모두 엔티티의 생성일/수정일을 자동으로 채우기 위한 것이다.

 

차이는 설정을 어디에 두느냐에 따라 테스트에 미치는 범위가 달라진다는 점이다.

방식 애플리케이션 실행 @WebMvcTest 테스트별 선택
메인 클래스에 @EnableJpaAuditing 정상 실패 불가 (모든 슬라이스에 적용)
메인 클래스 + 테스트마다 @MockitoBean 정상 통과 (매번 추가) 불가 (모든 슬라이스에 적용)
별도 JpaAuditingConfig 정상 통과 가능 (@Import)

 

나는 설정을 어디에 둘지 고민될 때 다음 기준으로 판단한다.

애플리케이션 전역 설정인가?    → 메인 클래스
특정 영역(JPA, 보안) 설정인가? → 별도 @Configuration 으로 분리
특정 테스트에서만 필요한가?    → @Import 로 가져온다

'Back-End > Spring' 카테고리의 다른 글

[OAuth 2.0] OAuth 2.0은 무엇이고 왜 사용할까  (0) 2026.10.23
[Spring Security] Spring Security는 왜 사용할까?  (0) 2026.10.23
[JPA] N+1 문제란 무엇일까?  (0) 2025.12.02
@RequestParam, @ModelAttribute, @RequestBody는 언제 사용할까?  (0) 2025.11.24
[JPA] @ManyToOne, @OneToMany 연관관계 정리  (0) 2025.11.22
'Back-End/Spring' 카테고리의 다른 글
  • [OAuth 2.0] OAuth 2.0은 무엇이고 왜 사용할까
  • [Spring Security] Spring Security는 왜 사용할까?
  • [JPA] N+1 문제란 무엇일까?
  • @RequestParam, @ModelAttribute, @RequestBody는 언제 사용할까?
devoks
devoks
느려도 꾸준히
  • devoks
    ok's 개발일지
    devoks
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Front-End
      • Back-End
        • Spring
        • Infra
        • AI
      • Computer Science
        • Cs
      • 언어
        • Java
        • SQL
      • 코테
        • Java
        • MySQL
      • Etc.
  • 블로그 메뉴

    • 홈
  • 링크

    • My GitHub
  • 공지사항

  • 인기 글

  • 태그

    PrePersist
    persist
    springboot
    java
    switch
    최대공약수
    replaceAll
    유클리드호제법
    정규표현식
    compare
    stack
    IaaS
    docker
    PaaS
    BufferedWriter
    BufferedReader
    역직렬화
    Regex
    StringTokenizer
    최대공배수
    effectivejava
    CS
    codingtest
    Container
    programmers
    dfs
    replace
    BFS
    CI/CD
    json
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
devoks
[Spring Boot] @EnableJpaAuditing이란?
상단으로

티스토리툴바