필터 ( includeFilters & excludeFilters )
includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.
<예제>
1. 어노테이션으로 MyIncludeComponent / MyExcludeComponent 생성.
2. 어노테이션 설정할 때, 기본 설정 어노테이션 3개 추가로 설정해준다.
@Target : 필드, 메소드, 클래스, 파라미터 등 선언할 수 있는 타입을 설정
@Retention : 어느 시점까지 어노테이션의 메모리를 가져갈지 설정
@Documented : javadoc의 부가기능 / 해당 애노테이션 정보를 해당 코드의 문서에 같이 보여준다.
(차후 @Documented는 따로 다뤄볼 예정)
<결과>
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
3. 해당 어노테이션을 각각 적용한 BeanA , BeanB 클래스 생성
BeanA → @MyIncludeComponent
BeanB → @MyExcludeComponent
package hello.core.scan.filter;
@MyIncludeComponent
public class BeanA {
}
package hello.core.scan.filter;
@MyExcludeComponent
public class BeanB {
}
4. 테스트 코드 작성
package hello.core.scan.filter;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.context.annotation.ComponentScan.*;
public class ComponentFilterAppConfigTest {
@Test
void filterScan() {
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
assertThat(beanA).isNotNull();
ac.getBean("beanB", BeanB.class);
}
@Configuration
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
static class ComponentFilterAppConfig{
}
}
<테스트 코드 설명>
MyIncludeComponent 어노테이션은 includeFilters 처리하고
MyExcludeComponent 어노테이션은 excludeFilters 처리했다.
따라서 MyIncludeComponent 어노테이션을 적용한 BeanA는 includeFilters에 의해 ComponentScan대상에 들어갈 것이고
MyExcludeComponent 어노테이션을 적용한 BeanB는 excludeFilters에 의해 스캔 대상에서 제외된다.
<TDD 결과>
해설 : 당연히 beanA는 bean객체로 적용이 될 것이고, beanB는 찾을 수 없게 된다.
FilterType 5가지 정리
- Annotation : 기본값임 ( 생략가능 ). 어노테이션을 인식하여 동작 (org.example.SomeAnnotation)
▶ 방법 1 = 방법 2
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다. (org.example.SomeClass)
- ASPECTJ: AspectJ 패턴 사용 (`org.example..*Service+`)
- REGEX: 정규 표현식 (`org\.example\.Default.*`)
- CUSTOM: `TypeFilter` 이라는 인터페이스를 구현해서 처리 (`org.example.MyTypeFilter)