스프링이 직접 클래스를 검색해서 빈으로 등록
해주는 기능기본 속성 값
으로 해당 클래스를 스캔 대상으로 지정
//MemberDao.java
import org.springframework.stereotype.Component;
@Component
public class MemberDao {
...
}
속성 값을 주어
스캔 대상으로 지정
//MemberInfoPrinter.java
// 빈의 이름을 지정
@Component("infoPrinter")
public class MemberInfoPrinter {
...
}
컴포넌트 스캔시 Bean의 이름이 지정되는 방법은 위의 두 가지 방법에 따라 아래와 같이 결정됨
첫 글자를 소문자
로 바꾼 이름 그 값을 Bean의 이름
으로 사용// AppCtx.java
import org.springframework.context.annotation.ComponentScan;
@Configuration
// ComponentScan 어노테이션
@ComponentScan(basePackages = {"spring"})
public class AppCtx {
/*
* 다음과 같은 코드가 줄어들게 됨
* public MemberDao memberDao(){
* ...
* }
* public MemberInfoPrinter memberInfoPrinter(){
* ...
* }
*/
@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
어노테이션으로 인해, 4장의 AppCtx 코드와 비교하여 설정 코드가 줄어듦
basePackage 속성값
은 {“spring”} 인데,그 패키지와 하위 패키지에 속한 클래스
를 스캔 대상으로 설정excludeFilters
속성을 사용하면 스캔할 때 특정 대상을 자동 등록 대상에서 제외 가능하고, 아래와 같이 3가지 사용법이 존재
각 방법별 사용 예시는 아래와 같음
정규 표현식 / AspectJ 패턴
을 사용한 대상 지정
// AppCtxWithExclude.java
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
// 동일 코드에 대하여 정규표현식 / AspectJ 패턴 사용 방식
// 정규표현식을 이용한 1번째 방법
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters =
(@Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao" )
)
// AspectJ를 이용한 2번째 방법
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters =
(@Filter(type = FilterType.ASPECTJ, pattern = "spring.*Dao" )
)
public class AppCtxWithExclude {
...
}
정규 표현식
은 “spring”으로 시작하고 Dao로 끝나는 타입을 지정AspectJ 패턴
은 spring 패키지의 Dao로 끝나는 타입을 지정특정 어노테이션
을 제외
// NoProduct.java
@Retention(RUNTIME)
@Target(TYPE)
public @interface NoProduct {
}
// ManualBean.java
@Retention(RUNTIME)
@Target(TYPE)
public @interface ManualBean {
}
위와 같은 특정 어노테이션을 붙인 타입을 텀포넌트 대상에서 제외하는 방법은 아래와 같이 존재
// AppCtxWithExclude.java
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = ManualBean.class )
})
FilterType.ANNOTATION
을 사용하면 class 속성에 필터로 사용할 어노테이션 타입
을 값으로 줌 // MemberDao.java
@ManualBean
@Component
public class Member Dao{
...
}
@Retention, @Target 어노테이션?
- 어노테이션을 Customizing 하는 방법
@Retention
:어느 시점
까지 어노테이션을 남길 것인가? (파라미터는 아래와 같음)
- SOURCE: 컴파일시 사라짐
- CLASS: 컴파일러가 클래스를 참조할 때까지 유효
- RUNTIME: 컴파일 이후에도 VM을 통해 참조 가능
@Target
:어디
에 우리가 만든 어노테이션을 적용할 것인가? (파라미터는 아래와 같음)
- TYPE: 클래스, 인터페이스
- FIELD: 필드
- METHOD: 매서드
- PARAMETER: 파라미터
- CONSTRUCTOR: 생성자
- LOCAL_VARIABLE: 지역변수
- ANNOTATION_TYPE: 어노테이션 타입
- PACKAGE: 패키지
특정 타입이나 그 하위 타입
을 제외
// AppCtxWithExclude.java
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters = {
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MemberDao.class )
})
제외할 타입
의 목록을 지정설정할 필터가 두 개 이상
이면 @ComponentScan의 exludeFilters 속성에 배열
을 사용해 @Filter 목록을 전달
// AppCtxWithExclude.java
@Configuration
@ComponentScan(basePackages = {"spring"},
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = ManualBean.class ),
(@Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao" )
})
컴포넌트 스캔 기능을 사용해서 Bean을 등록할 경우, 아래와 같은 두 가지 충돌이 발생 가능
서로 다른 패키지에 같은 클래스의 이름
이 존재하고, 두 클래스 모두 @Component 어노테이션이 붙게 된다면, 명시적
으로 Bean 이름을 지정해서 이름 충돌을 피해야 함수동 등록한 Bean이 우선
시 됨다른 이름의 두 개의 Bean
이 만들어지게 됨@Qualifier
어노테이션을 통해 알맞은 Bean을 선택해야 함