본문 바로가기
Backend, Server/Spring

[스프링] 컴포넌트 스캔, 탐색 위치, 중복 등록과 충돌

by ggyongi 2021. 12. 26.
반응형

목표

컴포넌트 스캔을 이용하여 자동으로 스프링 빈을 등록하게 하자!

추가로 @Autowired 기능을 사용하면 의존관계도 자동으로 주입할 수 있게 된다!

 

 

컴포넌트 스캔 사용법

설정 정보에 @ComponentScan을 붙여주면 된다.

이때 추가 파라미터로 excludeFilters, includeFilters 등을 추가할 수 있다.

@Configuration
@ComponentScan(
     excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {
}

그리고 스프링 빈으로 등록할 대상 클래스에 @Component을 달아주어야 한다.

@Component
public class MemoryMemberRepository implements MemberRepository {}

 

그렇다면 의존 관계는 어떻게 설정해야 할까?

기존의 @Bean으로 직접 설정 정보를 작성했을 땐, 의존 관계 역시 직접 명시해주었다.

하지만 컴포넌트 스캔 방식에서는 클래스 내에서 의존 관계 주입 문제를 해결해주어야 한다.

방법은 간단하다. 생성자에 @Autowired를 달아주면 끝이다.

그러면 스캐너가 보고 클래스 형식에 맞는 빈을 알아서 찾아 의존 관계를 주입시켜 준다.

(그러면 같은 클래스 형식이 여러개면 중복이 발생할 수도 있는데..? -> 나중에 배운다고 한다.)

@Component
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

 

* 스프링 빈에 등록 시에는 클래스 제일 앞글자만 소문자로 고쳐 등록하게 된다.

* @Component("...")로 직접 빈 이름을 설정 할 수도 있다.

 

 

탐색 위치

탐색 위치는 @ComponentScan(basePakages = "패키지주소")로 설정할 수 있다.

모든 자바 클래스를 탐색하면 시간이 매우 오래걸리기 때문이다.

사실 basePakages을 따로 설정하지 않으면 해당 설정 정보 클래스의 패키지가 시작 위치가 되기 때문에

basePakages를 따로 지정하지 않고 설정 정보 클래스를 프로젝트의 최상단에 두는 방법을 권장한다.

 

 

 

중복 등록과 충돌

 

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

서로 다른 클래스에 동일하게 @Component("service")을 추가했다고 하면?

컴포넌트 스캔 시 이름 중복으로 오류가 발생한다. (예외 : ConflictingBeanDefinitionException)

 

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

@Component
public class MemoryMemberRepository implements MemberRepository {}

 

@Configuration
@ComponentScan(
    excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {

    @Bean(name = "memoryMemberRepository")
    public MemberRepository memberRepository() {
    return new MemoryMemberRepository();
    }
}

위와 같은 상황에선 빈 이름이 둘 다 memoryMemberRepository로 등록되기 때문에 이름 중복이 발생한다.

스프링은 이 경우 예외를 발생시키지 않고 수동 빈 등록을 우선 시 한다. 즉 @Bean이 있는 클래스가 등록된다.

 

* 실제로 이런 상황은 의도치 않게 발생하기 때문에 수동과 자동이 충돌했을 때 이렇게 넘어가지 않고 그냥 충돌 오류를 발생시키도록 설정할 수도 있다.

* 스프링부트에서는 이 경우 충돌 오류가 발생하도록 기본값이 설정되어 있다.

 

 

 

------------------------

참고 : 인프런 김영한님 강의(스프링 핵심원리 기본편)

 

비전공자 네카라 신입 취업 노하우

시행착오 끝에 얻어낸 취업 노하우가 모두 담긴 전자책!

kmong.com

댓글