이 글을 읽기 전에 https://ksb-dev.tistory.com/313를 읽고 오시는 것을 추천드립니다.
💡 해당 글과 이 글의 내용은 매우 밀접하게 연관되어 있습니다.
1. 문제
Spring Boot와 Elasticsearch 연동을 테스트 하던 중 제목과 같은 에러를 만날 수 있었습니다.
패키지 구조는 아래와 같습니다.
es_springboot
-config
-AbstractElasticsearchConfiguration.java
-ElasticSearchConfig.java
-domain
-UserDocument.java
-repository
-UserSearchRepository.java
위 오류와 직접적으로 연관이 있는 클래스는 세 개 입니다.
@Configuration
@EnableElasticsearchRepositories
public class ElasticSearchConfig extends AbstractElasticsearchConfiguration {
@Override
public RestHighLevelClient elasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
@SpringBootApplication
public class EsSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(EsSpringBootApplication.class, args);
}
}
public interface UserSearchRepository extends ElasticsearchRepository<UserDocument, Long> {
}
맨 위의 링크에서 알 수 있듯이,
Spring Boot는 자동으로 @EnableJpaRepositories를 사용합니다.
@EnableJpaRepositories는 위 그림과 같이 JpaRepositoriesRegistrar를 Import하고, 해당 클래스는 ReposistoryBeanDefinitionRegistrarSupport를 상속 받습니다.
해당 클래스들로 빈이 정의되고, 프로그램을 실행할 때, 빈으로 등록됩니다.
@EnableElasticsearchRepositories를 살펴보겠습니다.
@EnableElasticsearchRepositories 역시 ReposistoryBeanDefinitionRegistrarSupport를 상속받고 있습니다.
즉, @EnableElasticsearchRepositories를 사용하면 빈으로 등록됩니다.
이제 문제가 발생합니다.
public interface UserSearchRepository extends ElasticsearchRepository<UserDocument, Long> {
}
위 코드는 Spring Boot에 의해 자동으로 빈 등록이 됩니다.
@Configuration
@EnableElasticsearchRepositories
public class ElasticSearchConfig extends AbstractElasticsearchConfiguration {
...
}
위 코드 역시 @EnableElasticsearchRepositories에 의해 빈으로 등록 됩니다.
즉, 빈 등록이 두 번 등록되어 제목과 같이 빈이 이미 정의되어 있다고 뜨는 것입니다.
💡 등록된 빈을 로그로 찍어본 결과 확실하지는 않지만, ElasticsearchRepositoryConfigExtension로 빈 등록이 되는거 같습니다. 정확히 아시는 분은 댓글 달아주시기 바랍니다.
2. 해결법
해결 방법은 간단합니다.
자동으로 빈 등록되지 않도록 하면 됩니다.
그렇게 되면 한 번만 빈 등록이 되기 때문에 문제를 해결할 수 있습니다.
아래 코드와 같이 스캔할 때, 엘라스틱서치와 관련된 것은 등록하지 않게 하면 됩니다.
@EnableJpaRepositories(excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserSearchRepository.class))
@SpringBootApplication
public class EsSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(EsSpringBootApplication.class, args);
}
}