본문 바로가기
Spring

자바 스프링 - 자동 빈 등록 @Component와 빈 스캔@ComponentScan 정리

by onggury 2023. 3. 31.

1. @Component 어노테이션

@Component 어노테이션은 타입 기반 자동 의존 주입 어노테이션입니다.

 

먼저 사용법에대해 글로 적어보자면,

 

 

- 자동 등록 되어야 하는 빈 클래스 바로 위에, @Component 어노테이션을 붙인다.
- 설정 클래스(@Configuration)에는 @ComponentScan 어노테이션을 이용해서 스캔 범위를 지정하면 등록할 Bean을 찾아서 자동으로 등록해준다.

 

즉, @ComponentScan 어노테이션은 스프링이 직접 클래스를 검색해서 Bean으로 등록해주는 기능입니다.

 

또한, 등록되는 Bean이름은 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 사용합니다.

 

 

그러면 예시를 보겠습니다.

// @Component 어노테이션 사용 클래스

@Component
public class MemberDao {
	...
}

@Component
public class ChangePasswordService {
	...
}

@Component
public class MemberRegisterService {
	...
}

/////////////////////////////////////////////////////////////////////////////////////

// @Component 어노테이션 속성 값 사용 클래스

@Component("infoPrinter")
public class MemberInfoPrinter {
	...
}

@Component("listPrinter")
public class MemberInfoPrinter {
	...
}

 

아까 설명했듯 @Component 어노테이션을 사용하면 클래스의 이름의 첫 글자를 소문자로 바꾼 이름을 Bean 이름으로 사용합니다.

그래서 해당 예시는 MemberDao, ChangePasswordService, MemberRegisterService는 각각 memberDao, changePasswordService, memberRegisterService가 Bean의 이름이 되겠죠.

 

 

위 예시에서 속성 값을 사용한 경우가 있는데

이때는 @Component 어노테이션 속성 값을 Bean 이름으로 사용합니다.

 

 


 

2. @ComponentScan 어노테이션

@ComponentScan 어노테이션으로 스캔 범위를 설정합니다.

 

이는 basePackages 속성 사용으로 패키지 목록을 지정할 수 있습니다.

 

@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppConfig {

	@Bean
    public MemberPrinter memberPrinter() {
    	return new MemberPrinter();
    }
}

위 예시는 @ComponentScan 어노테이션에 spring이란 패키지 이름을 속성 값에 넣음으로써

spring 패키지 안에서 등록할 Bean을 찾으라는 의미가 됩니다.

 

물론 대상 패키지 단위를 여러 개 지정 가능합니다.

 

 


 

3. @ComponentScan 어노테이션 충돌

 

@ComponentScan 어노테이션을 사용해서 자동으로 Bean을 등록할 땐 충돌에 주의해야 합니다.

 

 

 

1. Bean 이름 충돌

 

아래와 같이 서로 다른 두 개의 클래스가 있다고 가정합니다.

 

Package test.spring1

@Component
public class MemberRegisterService { ... }

////////////////////////////////////////////////////////////////////////////


Package test.spring2

@Component
public class MemberRegisterService { ... }

////////////////////////////////////////////////////////////////////////////


@Configuration
@ComponentScan(basePackages = {"spring1", "spring2"})
public class AppConfig { ... }

 

test.spring1 패키지와 test.spring2 패키지에는 둘 다 @Component 어노테이션이 붙어있죠.

 

그런데 MemberRegisterService 라는 같은이름의 클래스가 존재합니다.

 

이러면 BeanDefinitionStoreException 예외가 발생합니다.

 


 

2. 직접 등록한 빈과의 충돌

 

먼저 예시를 보겠습니다.

@Component
public class MemberDao { ... }

///////////////////////////////////////////////////////////////////////////


@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppConfig {

	@Bean
    public MemberDao memberDao() {
    	return new MemberDao();
    }
}

MemberDao 클래스는 자동 등록된 Bean이 될테고, 아래 설정 클래스(@Configuration)의 @Bean으로 직접 등록한 Bean이 있습니다.

 

이 때, 직접 등록한 Bean이 우선이 됩니다.

 

즉, MemberDao 타입의 Bean은 AppConfig에서 정의한 한 개만 존재합니다.

 

 

그런데 만약 위 코드와 같은 상황에서 클래스 이름과 Bean의 이름이 다르다면

MemberDao 타입의 빈이 두 개가 모두 생성됩니다.

그리고 자동 주입되는 Bean은 @Qualifier 어노테이션에 의해 결정되는 것입니다.