갑자기 왜 SpringBootApplication을 알아보는거죠?
- 코드 리뷰를 하는 중
SpringBootApplication
이 있는데,ComponentScan
,PropertySource
를 사용하는 이유가 무엇인지 질문이 들어왔을 때였다.
- 사실 난
SpringBootApplication
에 대하여 왜 이걸 쓰는지 누군가에게 설명 할 수 없단걸 깨달았고 이제 알아보려 한다.
@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 { ... }
위 코드는
SpringBootApplication
에 있는 annotation
들이다.이제 하나 씩 알아보도록 하겠다.
Documented
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
여기에 적당한 예제 코드와 설명이 있다.
JavaDoc으로 문서를 만들게 될 때, 어노테이션에 관한 설명도 포함되려면
Documented
가 필요하다.Inherited
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
여기에 적당한 예제 코드와 설명이 있다.
Inherited
어노테이션이 있으면 해당 어노테이션 인터페이스를 사용 할 수 있게 된다.Retention
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }
여기에 적당한 예제 코드와 설명이 있다.
이 어노테이션은 해당 어노테이션 인터페이스가
RetentionPolicy
에 명시한 것(SOURCE, CLASS, RUNTIME) 까지만 작동하는 것을 뜻한다.Target
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation interface * can be applied to. * @return an array of the kinds of elements an annotation interface * can be applied to */ ElementType[] value(); }
여기에 적당한 예제 코드와 설명이 있다.
해당 어노테이션에 ElementType이 명시되어 있다면 명시된 타입에만 사용 할 수 있다.
아래는
Target
어노테이션에 들어 갈 수 있는 enum constants 값들이다. ( 포함된 링크에도 있는 표지만 누락된 정보가 있어서 여기에 정리한다. )
Element Type | Element to be Annotated declaration |
Type | Class, Interface, Enum, Record declaration |
FIELD | Field declaration( includes enum constants) |
METHOD | Method declaration |
PARAMETER | Formal Parameter declaration |
CONSTRUCTOR | Constructor declaration |
LOCAL_VARIABLE | Local variable declaration |
ANNOTATION_TYPE | Annotation interface declaration |
PACKAGE | Package declaration |
TYPE_PARAMETER | Type parameter declaration |
TYPE_USE | Use of a type |
MODULE | Module declaration |
RECORD_COMPONENT | Record component |
- TYPE_PARAMETER가 쓰이는 곳은
class name<T1, T2, ..., Tn>
에서 T1, T2다.
- TYPE_USE가 쓰이는 곳은
@C int f;
에서 int다.
ComponentScan
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { ... }
여기에 적당한 예제 코드와 설명이 있다.
- 해당 어노테이션을 사용하면 스캔할 패키지를 명시할 수 있다.
- Exclude Filter, Include Filter, Filter로 필터링도 가능하다.
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
Repeatable
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { /** * Indicates the <em>containing annotation interface</em> for the * repeatable annotation interface. * @return the containing annotation interface */ Class<? extends Annotation> value(); }
여기에 참고 할 만한 자료가 있다.
해당 어노테이션을 사용하면 어노테이션들을 반복 적용 할 수 있게 해준다.
아래는
ComponentScan
에서 사용한 예시다.@AliasFor("classes") Class<?>[] value() default {};
SpringBootConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
주석에는 이렇게 설명이 달려있다.
Indicates that a class provides Spring Boot application @Configuration. Can be used as an alternative to the Spring's standard @Configuration annotation so that configuration can be found automatically (for example in tests).
간략하게 말하면 configuration 대신 알아서 bean들을 찾아 준다.
Configuration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor(annotation = Component.class) String value() default ""; boolean proxyBeanMethods() default true; }
주석에는 이렇게 설명이 달려있다.
Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime
해당 어노테이션을 사용하는 클래스에서 메서드에 Bean 어노테이션을 붙이면 런타임 시점에서 스프링 컨테이너에 빈을 등록해 준다.
Indexed
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Indexed { }
코드에 있는 주석을 읽어도 이해가 안간다.
다만, 구조상 Component 어노테이션이 해당 어노테이션을 사용한다.
- Component를 붙은 어노테이션은 스프링 컨테이너에 빈으로 등록 된다.
AliasFor
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { /** * Alias for {@link #attribute}. * <p>Intended to be used instead of {@link #attribute} when {@link #annotation} * is not declared — for example: {@code @AliasFor("value")} instead of * {@code @AliasFor(attribute = "value")}. */ @AliasFor("attribute") String value() default ""; /** * The name of the attribute that <em>this</em> attribute is an alias for. * @see #value */ @AliasFor("value") String attribute() default ""; /** * The type of annotation in which the aliased {@link #attribute} is declared. * <p>Defaults to {@link Annotation}, implying that the aliased attribute is * declared in the same annotation as <em>this</em> attribute. */ Class<? extends Annotation> annotation() default Annotation.class; }
아래는 해당 어노테이션의 주석 내용 중 일부다.
@AliasFor is an annotation that is used to declare aliases for annotation attributes.
SQL문을 작성할 때, 별칭(alias)를 사용하는 것과 똑같다.
주석에 있는 사용 예시는 총 4가지다.
- 어노테이션과 함께 명시적으로 사용
public @interface ContextConfiguration { @AliasFor("locations") String[] value() default {}; @AliasFor("value") String[] locations() default {}; // ... }
- 메타 어노테이션의 Attribute에 명시적으로 사용
@ContextConfiguration public @interface XmlTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xmlFiles(); }
- Implicit Aliases within an Annotation
@ContextConfiguration public @interface MyTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] value() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] groovyScripts() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xmlFiles() default {}; }
- Transitive Implicit Aliases within an Annotation
@MyTestConfig public @interface GroovyOrXmlTestConfig { @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts") String[] groovy() default {}; @AliasFor(annotation = ContextConfiguration.class, attribute = "locations") String[] xml() default {}; }
EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined.
AutoConfigurationPackage
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
Registers packages with AutoConfigurationPackages. When no base packages or base package classes are specified, the package of the annotated class is registered
Import
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { Class<?>[] value(); }
ndicates one or more component classes to import — typically @Configuration classes.