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 어노테이션에 의해 결정되는 것입니다.