티스토리 뷰

Web

Ch05. 컴포넌트 스캔

tose33 2022. 6. 24. 17:27

컴포넌트 스캔은 스프링이 직접 클래스를 검색(스캔)해서 빈으로 등록해주는 기능이다. 

스프링이 직접 빈으로 등록해주므로 컴포넌트 스캔을 사용하면 설정 클래스의 코드가 크게 줄어든다. 

 

@Component 애노테이션으로 스캔 대상 클래스 등록

컴포넌트 스캔은 클래스에 @Component 애노테이션을 붙여서 해당 클래스가 스캔 대상임을 알린다.

 

@Component("abc") 처럼 애노테이션에 값을 주면, 스캔 후 빈으로 등록할때 해당 값으로 빈 이름이 등록 된다.

@Component 처럼 값을 주지 않으면, 해당 클래스의 첫 문자를 소문자로 바꾼 이름을 빈 이름으로 등록한다. 

 

 

@ComponentScan 애노테이션으로 설정 클래스가 스캔하도록함

설정 클래스가 @Component 가 붙은 클래스를 스캔하도록 하려면, 설정 클래스에 @ComponentScan 애노테이션을 붙여줘야 한다.

@Configuration
@ComponentScan(basePackages = {"spring"}) // 스캔 대상 페키지 = spring
public class AppCtx
{
    @Bean
    @Qualifier("printer")
    public MemberPrinter memberPrinter1()
    {
        return new MemberPrinter();
    }

    @Bean
    @Qualifier("summaryPrinter")
    public MemberSummaryPrinter memberPrinter2()
    {
        return new MemberSummaryPrinter();
    }

    @Bean
    public VersionPrinter versionPrinter()
    {
        VersionPrinter versionPrinter = new VersionPrinter();
        versionPrinter.setMajorVersion(5);
        versionPrinter.setMinorVersion(0);
        return versionPrinter;
    }
}

@ComponentScan(basePackages = {"spring"})  의 의미는 "spring" 패키지와 그 하위 패키지가 스캔 대상이라는 뜻이다. 

 

즉 spring 패키지와 그 하위 패키지의 클래스 중 @Component 애노테이션이 붙은 클래스의 객체를 생성해서 빈으로 등록한다.

 

 

 

스캔 대상에서 제외하기

@ComponentScan 의 excludeFilters 속성을 사용해 스캔 시 제외할 대상을 설정할수 있다. 

@ComponentScan(basePackages = {"spring"}, 
        excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao"))

type 속성은 ANNOTATION, REGEX 등이 있는데 REGEX는 정규표현식을 사용해 제외 대상을 지정한다는 것을 의미한다.

pattern 속성은 type에 적용할 값을 선택한다. 여기서는 타입이 REGEX 였으므로 정규표현식이 전달된다. 

 

 

 

컴포넌트 스캔에 따른 충돌

1. 빈 이름 충돌

스캔 후 등록하려는 빈 이름이 같은 경우이다. 

spring 패키지에 Apple라는 클래스가 있다 = spring.Apple

spring2 패키지에 Apple라는 클래스가 있다 = spring2.Apple 

 

그리고 ComponentScan 속성을 다음과 같이 줬다.

@ComponentScan(basePackage = {"spring", "spring2"})

 

그러면 스프링은 spring과 spring2 패키지를 스캔해서 spring 패키지의 Apple을 apple로 빈 등록하고 (값을 주지 않으면 클래스의 첫 글자 소문자로 변경후 빈 등록), spring2 패키지의 Apple을 마찬가지로 apple로 빈 등록한다.

따라서 빈 이름 충돌이 일어난다.

 

이럴때는 하나를 명시적으로 빈 이름을 지정해줘야 한다.

= @Component("apple2") 

 

 

2. 수동 등록한 빈과 충돌

2-1. 두 이름이 같은 경우

@Component 애노테이션은 값을 지정해주지 않으면 해당 클래스의 첫 문자를 소문자로 변경 후 빈으로 등록한다.

만약 클래스에 @Component 애노테이션으로 자동 스캔 후 빈 등록 하도록 하고, 

설정 클래스에서 수동으로 빈 등록을 해주면 수동 등록한 빈을 우선한다.

 

@Component
public class MemberDao
{

MemberDao 클래스는 memberDao 라는 이름으로 빈이 등록된다.

그런데 설정 파일에서 아래와 같이 수동으로 memberDao라는 이름으로 또 등록해줬다.

@Bean 
public MemberDao memberDao()
{
    ...
}

이런 경우에는 수동 등록한 빈을 우선시해, MemberDao 타입의 빈은 memberDao 하나만 존재한다.

 

=> 두 이름이 같으면 하나만 등록됨 

 

 

2-2. 두 이름이 다른 경우

 

MemberDao 클래스:

@Component
public class MemberDao
{

 

설정 클래스:

@Bean 
public MemberDao memberDao2()
{
    ...
}

이렇게 되면 클래스 스캔 후 memberDao 라는 이름의 빈이 하나 등록되고,

설정 클래스에서 수동으로 등록된 memberDao2 라는 이름의 빈이 또 하나 등록된다.

 

=> 두 이름이 다르면 둘 다 등록됨 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함