Component scan
- 자동 주입과 함께 사용하는 추가 기능이 component scan이다.
- 스프링이 직접 클래스를 검색해서 bean으로 등록해주는 기능이다.
- bean 설정에 등록하지 않아도 원하는 클래스를 bean으로 등록할 수 있어 component scan을 사용하면 bean 설정 코드가 많이 줄어든다.
컴포넌트 스캔의 등록
1) @Component 으로 스캔 대상 지정
- 서비스 코드에 붙인다
@Component
public class MemberDao {
//..
}
이렇게 되면 bean이름은 “memberDao”로 자동지정된다. 자동 지정 규칙은 camelCase다.
- 아래와 같이 속성을 줄 수 있다
@Component("memberRepository")
public class MemberDao {
//..
}
속성을 지정하면 해당 이름으로 변경된다.
2) @ComponentScan 으로 스캔 설정
- bean 설정 코드에 아래와 같이 추가한다
@Configuration
@ComponentScan(basePackages = {"student"}) // <<< sudent패키지 하위의 클래스를 스캔 대상으로 한다.
public class AppContext {
//...
}
- 컴포넌트로 등록하면 bean설정 코드가 많이 줄어든다.
3) getBean()의 변경
- 컴포넌트로 bean 생성을 지정하게 되면 camelCase 이름을 가진다.
- 컴포넌트 스캔을 사용하고자 한다면, 기존의 getBean 메소드에서 bean 객체를 불러올때 설정한 닉네임을 없애거나 컴포넌트 속성의 값으로 맞춰야 한다.
// before (아무 속성을 주지 않았을때)
MemberRegisterService regSvc =
ctx.getBean("memberRegSvc", MemberRegisterService.class);
//after
MemberRegisterService regSvc =
ctx.getBean(MemberRegisterService.class);
스캔 대상의 필터링 (포함하기, 제외하기)
1) @ComponentScan(excludeFilters)
- 특정 bean 객체를 자동 등록 대상에서 제외할 수 있다.
a. 정규식 패턴
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" },
excludeFilters = {
@Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao")
})
public class AppCtxWithExclude {
//..
- 정규표현식으로 패턴으로 컴포넌트 스캔 대상을 필터링 한다.
- 위의 패턴은
spring.
으로 시작하고Dao
로 끝나는 클래스를 필터링 한다.
b. AspectJ 패턴
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" },
excludeFilters = {
@Filter(type = FilterType.ASPECTJ, pattern = "spring.*Dao")
})
public class AppCtxWithExclude {
- AspectJ 패턴은 정규식과 약간 다르다.
- pattern은
String[]
타입이라 한개 이상 지정할 수 있다 - 작동하려면 maven에 AspectJ를 추가해야한다.
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
c. 어노테이션 패턴
- 특정 어노테이션을 붙이면 제외되도록 할 수 있다.
- 먼저 아래와 같이 어노테이션을 만든다.
//ManualBean.class
@Retention(RUNTIME)
@Target(TYPE)
public @interface ManualBean {
}
- 그 다음 컴포넌트 스캔 설정의 필터에 아래와 같이 추가하면 된다.
- 여러개의 어노테이션 등록도 가능하다
{class1,class2}
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" },
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = ManualBean.class )
})
public class AppCtxWithExclude {
//...
d. Assignable_type 패턴
@Configuration
@ComponentScan(basePackages = {"spring", "spring2" },
excludeFilters = {
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MemberDao.class )
})
public class AppCtxWithExclude {
//...
- 위와 같이 클래스 자체를 지정해서 제외할 수도 있다.
기본 스캔 대상
- 스프링에서 @Component 이외에 스캔대상으로 자동 편입하는 어노테이션이 몇가지 더 있다
- @Component
- @Controller
- @Service
- @Repository
- @Aspect
- @Configuration
컴포넌트 충돌 T/S
1) bean 이름 충돌
- 컴포넌트 스캔을 여러개 하는 경우 같은 클래스를 등록하려는 경우가 있는데 이럴때는 명시적으로 이름을 등록해야한다
getBean()
2) 수동 등록한 bean과 충돌
- bean 등록시 수동으로 명시한 bean을 우선순위로 등록한다.
- 같은 객체를 바라보는 경우는 @Qualifier로 알맞은 bean을 선택해야 한다.