Filter Annotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//@ComponentScan에 중첩 클래스로 있다
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
/**
* The type of filter to use.
* <p>Default is {@link FilterType#ANNOTATION}.
* @see #classes
* @see #pattern
*/
FilterType type() default FilterType.ANNOTATION;
/**
* Alias for {@link #classes}.
* @see #classes
*/
@AliasFor("classes")
Class<?>[] value() default {};
/**
* The class or classes to use as the filter.
* <p>The following table explains how the classes will be interpreted
* based on the configured value of the {@link #type} attribute.
* <table border="1">
* <tr><th>{@code FilterType}</th><th>Class Interpreted As</th></tr>
* <tr><td>{@link FilterType#ANNOTATION ANNOTATION}</td>
* <td>the annotation itself</td></tr>
* <tr><td>{@link FilterType#ASSIGNABLE_TYPE ASSIGNABLE_TYPE}</td>
* <td>the type that detected components should be assignable to</td></tr>
* <tr><td>{@link FilterType#CUSTOM CUSTOM}</td>
* <td>an implementation of {@link TypeFilter}</td></tr>
* </table>
* <p>When multiple classes are specified, <em>OR</em> logic is applied
* — for example, "include types annotated with {@code @Foo} OR {@code @Bar}".
* <p>Custom {@link TypeFilter TypeFilters} may optionally implement any of the
* following {@link org.springframework.beans.factory.Aware Aware} interfaces, and
* their respective methods will be called prior to {@link TypeFilter#match match}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
* </ul>
* <p>Specifying zero classes is permitted but will have no effect on component
* scanning.
* @since 4.2
* @see #value
* @see #type
*/
@AliasFor("value")
Class<?>[] classes() default {};
/**
* The pattern (or patterns) to use for the filter, as an alternative
* to specifying a Class {@link #value}.
* <p>If {@link #type} is set to {@link FilterType#ASPECTJ ASPECTJ},
* this is an AspectJ type pattern expression. If {@link #type} is
* set to {@link FilterType#REGEX REGEX}, this is a regex pattern
* for the fully-qualified class names to match.
* @see #type
* @see #classes
*/
String[] pattern() default {};
}
필터라는 것은 아래와 같이 쓰인다
1
2
3
4
5
6
7
8
9
10
11
12
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)})
public @interface SpringBootApplication {
//자세한 내용은 생략
}
includeFilter 와 excludeFilter
위에 보면 excludeFilter가 보이는데 이는 ComponentScan에 포함시키지 않는다는 의미이다. 반대로 includeFilter라는 기능도 있는데 이는 ComponentScan에 포함시킨다는 기능이다.
1
2
3
@ComponentScan(
includeFilters = {
@Filter(type = FilterType.상수, classes = 클래스명.class)})
1
2
3
@ComponentScan(
excludeFilters = {
@Filter(type = FilterType.상수, classes = 클래스명.class)})
- 각각 ComponentScan의 대상이지만 제외시키거나 포함시켜야할 때 사용한다.
- Type은 ComponentScan에 포함/제외 기준 설정이며 이 값은 Spring에서 상수로 제공한다.
- classes는 ComponentScan에 포함/제외할 특정 클래스를 명시하는 설정이다
FilterType의 옵션
총 다섯가지의 옵션이 있다
옵션 | 설명 | 예시 |
---|---|---|
FilterType.ANNOTATION | annotation을 기준으로 인식한다 (default 설정이므로 생략 가능하다) | org.example.SomAnnotation |
FilterType.ASSIGNABLE_TYPE | 지정한 타입과 자식 타입까지 인식한다 | org.example.SomeClass |
FilterType.ASPECTJ | AspectJ 패턴을 사용한다 | org.example..*Service+ |
FilterType.REGEX | 정규표현식을 사용한다 | org.example.Default.* |
FilterType.CUSTOM | TypeFilter라는 인터페이스를 구현하여 사용한다 | org.example.ExampleFilter |
그렇다면 이 기능은 언제 사용될까?
패키기를 따라서 ComponentScan이 동작하다가 이 Annotation이 붙은 클래스를 ComponentScan할 때 사용된다. 이때 @Filter의 옵션을 보고 어떻게 빈으로 등록할지 결정한다.
예제 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = CustomIncludeComponent.class)
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = CustomExcludeComponent.class)
}
)
public @interface MySpringBootApplication {
}
ComponentScan을 따로 해줄 @SpringBootApplication과 비슷한 애노테이션을 만든다
1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExcludeComponent {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomIncludeComponent {
}
그리고 컴포넌트 스캔을 할지 안할지 결정해주는 애노테이션도 만들어준다
1
2
3
4
5
6
7
8
9
10
11
12
13
@CustomExcludeComponent
public class ExcludeClass {
public ExcludeClass() {
System.out.println("ExcludeClass Generated");
}
}
@CustomIncludeComponent
public class IncludeClass {
public IncludeClass() {
System.out.println("IncludeClass Generated");
}
}
위의 애노테이션들을 각각의 클래스에 적용해준 후에
1
2
3
4
5
6
7
@MySpringBootApplication
public class DemoSpringApplication {
public static void main(String[] args) {
SpringApplication.run(DemoSpringApplication.class, args);
}
}
이 코드에 적용하면
1
2
3
4
5
6
7
8
9
10
11
12
13
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.0)
2023-12-02T10:19:55.186+09:00 INFO 37628 --- [ main] c.e.demospring.DemoSpringApplication : Starting DemoSpringApplication using Java 18.0.1.1 with PID 37628 (C:\Users\usr\IdeaProjects\demoSpring\build\classes\java\main started by usr in C:\Users\usr\IdeaProjects\demoSpring)
2023-12-02T10:19:55.188+09:00 INFO 37628 --- [ main] c.e.demospring.DemoSpringApplication : No active profile set, falling back to 1 default profile: "default"
2023-12-02T10:19:55.188+09:00 DEBUG 37628 --- [ main] o.s.boot.SpringApplication : Loading source class com.example.demospring.DemoSpringApplication
IncludeClass Generated
2023-12-02T10:19:55.497+09:00 DEBUG 37628 --- [ main] inMXBeanRegistrar$SpringApplicationAdmin : Application Admin MBean registered with name 'org.springframework.boot:type=Admin,name=SpringApplication'
위와 같은 로그가 찍히면서 IncludeClass가 생성됨을 알 수 있다.
This post is licensed under CC BY 4.0 by the author.