프로그래밍/Spring

[Spring] 8. 컴포넌트와 컴포넌트 스캔

EVEerNew 2022. 6. 28. 13:50
반응형

 

 

 

* 김영한님의 스프링 핵심원리 기본편 강좌를 수강하며 정리한 글입니다. *

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

 

 

 

이전 글에서는 싱글톤 패턴과 스프링 컨테이너의 원리에 대하여 정리했다.

 

 

컴포넌트와 스캔

 

스프링 빈은 설정 정보를 @Bean으로 일일이 등록을 해주어야 한다.

이를 편리하게 자동으로 등록해주는 것이 컴포넌트 스캔이다.

 

설정 정보 클래스에 @ComponentScan 어노테이션을 추가로 붙여주면,

해당 설정 정보를 사용해 스프링 컨테이너 생성 시 모든 클래스를 대상으로 컴포넌트 스캔이 진행된다.

 

이제 클래스가 컴포넌트 스캔의 대상이 되도록 @Component 어노테이션을 추가하면 빈으로 등록된다.

하지만 설정 정보에서는 의존관계가 설정되어 있었다.

 

 

예를 들어 MemberServiceImpl를 생성할 때는 memberRepository를 컨테이너에서 자동으로 주입받았다.

@Bean
public MemberService memberService(){
	//memberRepository()를 주입받음
    return new MemberServiceImpl(memberRepository());
}

 

클래스별로 컴포넌트 등록을 한다면 DI(의존성 주입)은 어떻게 해결해야 할까?

이를 해결해 주는 것이 바로 @Autowired 어노테이션이다.

 

MemberServiceImpl의 생성자에  @Autowired를 붙여주면 스프링 생성 시 의존관계가 자동 주입된다.

@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
    this.memberRepository = memberRepository;
}

 

 

 

컨테이너가 의존관계를 주입하는 순서는 다음과 같다.

 

1.  @ComponentScan 이 붙은 설정 정보로 컨테이너 생성

new AnnotationConfigApplicationContext(AutoAppConfig.class);

2. 모든 클래스를 확인하여 @Component 가 붙은 클래스를 빈으로 등록

  이때 등록되는 빈의 이름은 class의 앞 글자만 소문자로 바꾸어 등록된다.

 ( Member -> member)

 

3. 생성자에 @AutoWired가 붙으면 스프링 컨테이너가 해당 빈을 찾아 자동으로 주입

 따라서 싱글톤이 지켜진다.

 

 

 

스캔 위치 지정과 대상

 

@ComponentScan에는 여러 옵션도 적용 가능하다.

특히 스캔 대상 패키지는 basePackages = "PATH"  또는 {"PATH1", "PATH2" ... }로 설정 가능하다.

basePackageClasses = class 는 해당 class의 패키지를 기본 탐색 위치로 설정한다.

 

@Configuration
@ComponentScan( basePackages = "hello.core.member")
// member 패키지 하위의 class만 스캔됨
public class AutoAppConfig {

}

만약 스캔 위치를 지정하지 않는다면, @ComponentScan 설정 정보 클래스의 패키지가 탐색 위치가 된다.

관례적으로 탐색 위치 설정보단, 설정 정보 클래스를 루트 패키지에 두어 사용한다.

 

 

사실, 스프링 부트를 사용한다면 @SpringBootApplication에는 @ComponentScan이 적용되어 있다.

따라서 @SpringBootApplication 이 적용된 클래스의 패키지가 자동으로 스캔 위치로 설정된다.

 

 

컴포넌트 스캔은 @Component 가 적용된 클래스를 등록하는데

@Controller, @Service, @Repository, @Configuration 에도 @Component가 적용되어 있다.

따라서 위의 어노테이션 적용 시 자동으로 스캔의 대상이 된다.

 

사실 어노테이션은 순수 자바에서는 주석의 역할(메타 정보)로 사용되지만, 위와 같은 복잡한 기능이 도대체 뭔가 생각이 들 수 있다. 이는 스프링에서 지원하는 기능으로 서로 연결하여 부가 기능을 수행해 준다.

 

 

컴포넌트 스캔 필터

 

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.옵션,
    classes = 포함 시킬.class),
    excludeFilters = @ComponentScan.Filter(type = FilterType.옵션,
    classes = 배제 시킬.class)
)
static class ComponentFilterAppConfig{
}

includeFilters는 빈으로 등록시킬 클래스

excludeFilters는 빈 등록에서 배제시킬 클래스를 필터로 설정할 수 있다.

 

필터의 옵션으로는 5가 존재한다.

ANNOTATION: default 옵션으로 어노테이션을 인식

ASSIGNABLE_TYPE: 지정한 클래스 타입 인식

ASPECTJ:  AspectJ 패턴 사용

REGEX: 정규 표현식 

CUSTOM: 직접 filter 인터페이스 구현해 적용

 

하지만 기본 설정에 맞추어 진행하는 상황이 많다.

 

 

@Component("빈 이름")으로 이름 설정도 가능하다.

단, 중복된 이름이 있다면 컴포넌트 스캔 시 다음 오류가 발생한다.

ConflictingBeanDefinitionException: Annotation-specified bean name

 

하지만 @Bean과 @Component 간의 이름 중복은 수동 빈(@Bean)이 자동 빈(@Component)을 오버라이딩 하여 오류가 발생하지 않는다.

물론, 오류 발생 없이 오버라이딩이 되어 버리면 개발자는 어떤 문제가 일어났는지도 알기 힘들 것이다.

따라서 스프링 부트는 오류를 발생시키도록 변경되었다.

 

 

 

 

반응형