본문 바로가기
Develop/Spring (이론)

@componentScan 중복 등록과 충돌

by 보보트레인 2023. 8. 20.

@componentScan 을 실행할 때, bean이름 중복 등록과 충돌이 일어나면 스프링은 어떻게 대응할까?


1. 자동 빈 등록 vs 자동 빈 등록 상황

중복되는 두개의 빈이 모두 자동등록 되는 경우 ( @Component 어노테이션을 통해서... )

→ 오류 발생 :  ConflictingBeanDefinitionException` 예외 발생

 

OrderServiceImpl의 @Bean명을 "service"로 설정
MemberServiceImpl의 @Bean명을 "service"로 설정

두개의 service명이 겹칠 때, bean을 조회하는 scan 테스트 코드를 실행 시 오류가 뜸.

 

<테스트 코드>

package hello.core.scan;

import hello.core.AutoAppConfig;
import hello.core.member.MemberService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AutoAppConfigTest {

    @Test
    void basicScan() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

        MemberService memberService = ac.getBean(MemberService.class);
        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
    }
}

<결과>

BeanDefinitionException발생
service라는 중복되는 bean name이 원인인 것을 확인할 수 있다.


2. 수동 빈 등록 vs 자동 빈 등록

@Configuration을 통해 @Bean으로 수동등록되어 있는 경우의 빈 이름과 @Component어노테이션으로 자동등록된 빈 이름이 충돌할 경우 → 수동등록이 우선권을 가진다 ( 수동등록 bean name이 자동등록 bean name을 오버라이딩한다

 

<예시>

기존의 MemoryMemberRepository는 @Component에 의해 자동등록될 때

자동등록 bean name은 당연히 빈 이름 기본전략에 의거하여 memoryMemberRepository로 생성될 것.

 

참고글 : https://iron-mentalman.tistory.com/entry/ComponentScan%EA%B3%BC-%EC%9D%98%EC%A1%B4-%EA%B4%80%EA%B3%84-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85%ED%95%98%EA%B8%B0

 

@ComponentScan & 의존성 주입(@Autowired) 딥다이브

지금까지 스프링 빈을 등록할 때는 자바코드의 @Bean이나 XML의 을 통해서 설정 정보에 직접 등록할 스프링 빈을 나열했다. 이렇게 등록해야할 스프링 빈이 수십, 수백개가 되면 일일이 등록하기

iron-mentalman.tistory.com

 

따라서 다른 아무개 클래스 파일의 bean name을 memoryMemberRepository로 설정하고,

 bean을 조회하는 테스트 코드를 실행하면

테스트는 성공하지만 오버라이딩 되었다는 결과를 확인할 수 있다.


하지만 !!!

 

현실은 개발자가 의도적으로 설정해서 이런 결과가 만들어지기 보다는,

여러 설정들이 꼬여서 이런 결과가 만들어지는 경우가 대부분이라고 한다. (악성 버그로의 진화 가능성 농후..)

그래서 최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값을 바꾸었다.

 

<증명>

@SpringBootApplication을 통해 @ComponentScan을 실행해보자\

이전에 공부해서 알다시피 @SpringBootApplication에도 @ComponentScan이 있다는 것을 우리는 안다.

 

<결과>

이미 정의된 이름이라고 오류가 뜬다.

이렇게 스프링부트는 애초에 악성버그로 진화할 요인이 있는 것을 미연에 방지하도록 조치하고 있다.

 

만약 그럼에도 오버라이드 해서 오류를 없애고 싶다면?

→ 오류 콘솔의 빨간 동그라미 부분을 resource > application.properties에 복사 붙혀넣기 후 실행하면 된다.

해당부분을 (spring.main.allow-bean-definition-overriding=true )

이렇게 복사붙혀넣기 하고 다시 CoreApplication의 @SpringBootApplication를 실행하면

문제없이 실행됨을 확인할 수 있다.

 

 

결론: 애초에 bean name을 겹치지 않게 심혈을 기울여서 잘 만들자! 

반응형