본문 바로가기
Spring

[Spring] @EnableJpaRepositories bootstrapMode 정리

by 노력남자 2023. 7. 9.
반응형

이번 포스팅에선 @EnableJpaRepositories 옵션인 bootstrapMode에 대해서 알아보겠다.

 

BootstrapMode란?

 

Spring Data JPA 공식 문서에 있는 소개글로 BootstrapMode가 뭔지 알아보자.

 

기본적으로 Spring Data JPA 리포지토리는 기본적인 Spring 빈입니다. 이들은 싱글톤 범위로 설정되어 있으며, 즉시 초기화됩니다. 시작 시점에서 JPA EntityManager와 상호작용하여 유효성 검사 및 메타데이터 분석에 사용됩니다. Spring Framework는 Spring 애플리케이션의 시작 시간을 상당히 소요하는 JPA EntityManagerFactory의 초기화를 백그라운드 스레드에서 지원합니다. 이러한 백그라운드 초기화를 효과적으로 활용하려면 JPA 리포지토리가 가능한 늦게 초기화되도록 해야 합니다.

Spring Data JPA 2.1부터는 BootstrapMode를 구성할 수 있습니다. @EnableJpaRepositories 주석이나 XML 네임스페이스를 통해 다음과 같은 값을 설정할 수 있습니다:

 

  • DEFAULT (기본값): 리포지토리는 명시적으로 @Lazy로 주석이 달려 있지 않으면 즉시 인스턴스화됩니다. 리포지토리 빈의 초기화는 해당 리포지토리 인스턴스를 필요로하는 클라이언트 빈이 없는 경우에만 지연됩니다. 클라이언트 빈이 리포지토리 인스턴스를 필요로하는 경우, 리포지토리 빈은 초기화됩니다.
  • LAZY: 모든 리포지토리 빈을 암묵적으로 지연으로 선언하며, 클라이언트 빈에 주입되는 지연 초기화 프록시도 생성됩니다. 이는 클라이언트 빈이 리포지토리를 초기화 중에 사용하지 않고 단순히 인스턴스를 필드에 저장하는 경우, 리포지토리가 인스턴스화되지 않음을 의미합니다. 리포지토리 인스턴스는 리포지토리와의 첫 상호작용 시 초기화 및 검증됩니다.
  • DEFERRED: LAZY와 기본적인 동작 모드는 동일하지만, 애플리케이션이 완전히 시작되기 전에 리포지토리 초기화를 트리거하는 ContextRefreshedEvent에 응답하여 리포지토리가 검증됩니다.

 

권장사항:


비동기 JPA 부트스트랩을 사용하지 않는 경우에는 기본 부트스트랩 모드를 유지하십시오.


JPA를 비동기적으로 부트스트랩하는 경우, DEFERRED는 합리적인 기본값입니다. 이렇게 함으로써 Spring Data JPA 부트스트랩은 EntityManagerFactory 설정에 대해 다른 모든 애플리케이션 구성 요소의 초기화보다 더 오래 걸리는 경우에만 대기합니다. 그러나 리포지토리가 올바르게 초기화되고 검증되기 전에 애플리케이션이 시작됨을 보장합니다.


LAZY는 테스트 시나리오와 로컬 개발에 적합한 선택입니다. 리포지토리가 올바르게 부트스트랩될 수 있다고 확신하는 경우나 애플리케이션의 다른 부분을 테스트하는 경우에는 모든 리포지토리에 대한 검증은 시작 시간을 불필요하게 증가시킬 수 있습니다. 동일한 원리가 단일 리포지토리의 초기화가 필요한 애플리케이션 일부에만 액세스하는 로컬 개발에도 적용됩니다.

 

BootstrapMode 설정 방법

 

두 가지 방법이 있다.

 

- application.yml

 

spring:
  data:
    jpa:
      repositories:
        bootstrap-mode: LAZY

 

- application.kt

 

@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
@SpringBootApplication
class Application

fun main(args: Array<String>) {
	runApplication<Application>(*args)
}

 

추가로 각 테스트에 붙여서 쓸 수도 있다.

 

@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
@SpringBootTest
class AddressRepositoryTest() { ... }

 

무엇을 초기화 해주는 걸까?

 

위에서 BootstrapMode에 대해 알아봤는데 그럼 도대체 어떤 걸 초기화해주길래 저런 모드가 별도로 있는 걸까?

 

RepositoryFactorySupport 클래스의 getRepository() 메소드에서 확인할 수 있었다.

 

 

너무 길어서 다 올리진 않았다. 시간있으면 들어가서 보자.

 

Repository (CrudRepository, PagingAndSortingRepository, JpaRepository 등) 구성에 필요한 것들을 설정해준다.

 

너무 많아서 다 볼 수는 없었지만 대략 보면

 

  • 메타데이터 설정
  • 쿼리 검증
  • QueryDSL 구현체 설정
  • Repository advice 설정

 

위에 적어놓은 거말고 몇 가지를 더 해주는데 딱히 몰라도 될 거 같다.

 

BootstrapMode 테스트

 

logging level을 debug로 설정하고 올려야 repository 초기화 로그가 나온다.

 

미리 생성해놓은 AddressRepository로 테스트를 해보겠다.

 

- DEFAULT

 

어떤 설정도 하지 않으면 BootstrapMode.DEFAULT로 실행된다.

 

서버를 올리자마자 바로 AddressRepository가 초기화 된 걸 볼 수 있다.

 

 

- LAZY

 

Test 클래스에 @EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)를 붙였다.

 

이번엔 서버를 올리지 않고 테스트를 돌려보겠다.

 

@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
@SpringBootTest
class AddressRepositoryTest(
    @Autowired
    private val addressRepository: AddressRepository,
) {

    @Test
    fun testLazyInit() {
        addressRepository.findById(1)
    }
}

 

로그를 보면

 

lazy로 설정해놔서 proxy를 주입했다는 로그가 먼저 나오고

 

 

테스트가 실행되기 전 바로 초기화가 일어나는 걸 볼 수 있다.

 

 

- DEFERRED

 

Repository를 비동기로 초기화할 때 사용하는 DEFERRED는 LAZY와 동일해서 설정 방법만 알아보겠다.

 

entityManagerFactory에 bootstrapExecutor에 비동기 로직을 넣어줘야 한다.

 

delayedTaksExecutor 빈을 만들고 그걸 주입해주자.

 

@Bean
fun delayedTaskExecutor(): AsyncTaskExecutor {
    return object : ThreadPoolTaskExecutor() {
        override fun <T> submit(task: Callable<T>): Future<T> {
            return super.submit(Callable {
                Thread.sleep(5000)
                task.call()
            })
        }
    }
}

@Bean
fun entityManagerFactory(
    dataSource: DataSource,
    delayedTaskExecutor: AsyncTaskExecutor
) = LocalContainerEntityManagerFactoryBean().apply {
    bootstrapExecutor = delayedTaskExecutor
}

 

결론

 

DEFAULT

 

비동기 초기화를 사용하지 않는 경우 사용

 

LAZY

 

배치, 테스트 환경에 사용

 

DEFERRED

 

운영에서 Repository 비동기로 초기화 하는 경우 사용

 

References

- https://docs.spring.io/spring-data/jpa/docs/current-SNAPSHOT/reference/html/#jpa.bootstrap-mode

- https://www.baeldung.com/jpa-bootstrap-mode

반응형

댓글