DataSource가 2개 이상일 때의 Auto-Configure

YoonJuHo·2025년 3월 17일
post-thumbnail

오늘의 목표

DataSource가 2개 이상일때 자동구성 과정 알아보기

일전에 Data JPA를 사용한 환경에서의 자동구성 과정 를 통해 자동 구성에서 호출되는 클래스와 등록되는 빈들을 살펴보았습니다. 실제 프로젝트에서는 단일 데이터베이스 대신 리플리케이션 등 다중화 작업을 진행하는 경우가 많다고 생각합니다. 그래서 이번에는 하나의 DataSource가 아닌, 여러 DataSource가 등록된 환경에서 자동 구성이 어떻게 이루어지는지 알아보겠습니다. (짧음 주의)

리플리케이션 환경 구성

yml 파일

우선 여러개의 DataSource를 등록해놓아야 하는 상태이므로 아래와 같이 yml 파일을 설정해 주었습니다.
(간단하게 Reader DBWriter DB로 구성해놓았습니다.)

production code

  • 여러 DataSource(읽기와 쓰기)를 동적으로 라우팅하고, LazyConnectionDataSourceProxy를 통해 실제 연결 시점을 늦춤으로써, 트랜잭션이나 데이터베이스 작업이 실제로 필요할 때까지 연결을 열지 않도록 합니다.
  • 이 방식은 런타임에 어떤 데이터 소스를 사용할지 결정할 수 있게 해주며, 예를 들어 쓰기 작업은 writer, 읽기 작업은 reader로 분리할 수 있습니다.

이와 같이 설정한 후 테스트를 수행해보면 정상적으로 테스트가 통과되는 것을 알 수 있습니다.
또한, 아래 콘솔에 출력된 Bean을 확인해보니 LazyConnectionDataSourceProxy 가 반환된 것을 알 수 있습니다.

DataSource Bean을 따로 생성하지 않는다면?

production code를 모두 지우고 다시 테스트를 수행하면 DataSource를 특정지을 수 없다는 에러 메세지가 나오게 되는데요.

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class

단일 DataSource 설정이 있으면 Spring Boot의 자동 구성에 의해 기본 DataSource 빈이 생성되지만, 두 개 이상의 DataSource가 존재하면 어떤 DataSource를 기본으로 사용할지 결정할 수 없어서 "DataSource를 특정지을 수 없습니다"라는 에러가 발생하였습니다.
이를 해결하려면, 여러 DataSource 중 하나(아까의 LazyConnectionDataSourceProxy)를 @Primary로 지정하거나, 명시적으로 기본 DataSource를 선택할 수 있는 추가 구성을 해야 합니다.

예외 메세지를 더 살펴보자면,

  • 빨간색 박스를 자세히 보면 dataSourceInitializationConfigurationdataSourceScriptDatabaseInitializer() 메서드의 첫번재 인자로 DataSource가 들어와야 하는데 해당 DataSource가 정상적으로 생성이 되지 않았다는 예외 메세지가 존재합니다.
  • 예외를 따라가다보면 DataSourceConfiguration 클래스가 보이게 됩니다. Data JPA를 사용한 환경에서의 자동구성 과정 에서도 다뤘다시피 DataSourceConfigurationDataSource를 생성하는 곳이지만 생성이 이루어지지 않았습니다.
  • 애초에 DataSourceProperties 에 내부 값들이 null로 입력된 것을 알 수 있습니다.

    @ConfigurationProperties(prefix = "spring.datasource") 어노테이션은 Spring Boot에서 외부 설정 파일(예: application.yml 또는 application.properties)에 정의된 spring.datasource로 시작하는 속성들을 Java 객체의 필드에 바인딩하기 위해 사용되지만,
    현재는 DataSource를 2개 정의하는 바람에 해당 속성을 사용하지 못하였기에 자동으로 DataSource를 설정할 수 없었습니다.

DataSource를 2개 이상 자동구성 할 수 있게 스프링이 지원해줄수는 없나?

SpringGitHub 이슈에서는 현재까지도 다중 DataSource 자동 구성에 대한 논의가 활발히 이어지고 있음을 확인할 수 있습니다.

스프링 이슈 바로가기

어떻게 해결하지?

제가 선택한 해결 방법은 단순합니다.
기존에 자동구성으로 DataSource가 생성되고, EntityManagerFactory가 생성되고, JpaTransactionManager가 생성이 되었기에, DataSource만 따로 정의한 빈이 등록되게 하고, 나머지 JpaTransactionManagerEntityManagerFactoryJPA 관련 빈들은 Spring Boot가 생성되게 구성하는 것으로 해결하고자 하였습니다. 따라서 여러 DataSource를 빈으로 생성한 후 @Primary를 통해 빈에 우선권을 주었습니다.

개발자가 정의한 Component들이 먼저 스캔 돼서 Bean으로 등록된 후에, AutoConfigurationBean들이 등록되기 때문에 @ConditionalOnSingleCandidate(DataSource.class) 을 사용하는 (예시:HibernateJpaConfiguration) 클래스들의 조건만 만족시켜주면 스프링 부트의 자동구성을 이용할 수 있습니다.

0개의 댓글