
이전 글에서 SprinbBoot 3.3.4 코드를 분석할 순서를 정했다.
spring-boot-autoconfigure:http 를 까보던중 SpringBoot 를 이용해 코드를 쓸때 직접적으로 사용하지 않았던 생소한 어노테이션들이 있어서 우선 이 어노테이션들을 정리한다.
그 목록은 다음과 같다.
- @AutoConfiguration
- @AutoConfigurationBefore, @AutoConfigurationAfter
- @ConditionalOnClass, @ConditionalOnMissingBean
그리고 이렇게 공부한 내용이 실무에서는 어떤식으로 영향을 끼치고 있는지 살펴본다.
어노테이션 살펴보기
1. @AutoConfiguration
설명
이 어노테이션이은 해당 클래스가 클래스 스프링 부트 프레임워크에 의해 자동으로 적용되는 설정을 담고 있음을 명시한다. 보통은 @Configuration 어노테이션에 의해서 설정되지만 '이 어노테이션을 통해서 설정하면 proxyBeanMethod = false 로 설정되는 예외가 있습니다.'(의역, 추측)
AutoConfiguration 으로 표시된 클래스는 보통 @Conditional, @ConditionalOnClass, @ConditionalOnMissingBean 과 함께 사용된다.
* proxyBeanMethod = false 의 의미
@Configuration 어노테이션은 SpringBoot를 통해 어플리케이션을 만들 때 개발자가 종종 사용하는 어노테이션일 것이다. 이 어노테이션은 별도의 설정이 없다면 'proxyBeanMethod = true'가 기본값으로 설정되어 특수한 행위를 강제하는데, @Configuration이 명시된 클래스 내부에서 정의한 @Bean들이 싱글톤(Shared Singleton Bean)으로 유지될 수 있도록 런타임에 CGLIB를 통해 프록시로 감싸버린다.
따라서 'proxyBeanMethod = false'로 표시하는 것은 해당 클래스에서 정의된 Bean의 scope를 Shared Singleton Bean으로 만들지 않겠다는 것을 의미한다. 등록하려는 Bean을 프록시로 감싸지 않기 때문에 Bean을 등록할 때 오버헤드가 감소하여 성능상 이점이 있겠으나, 생성 비용이 비싼 Bean을 등록하는 데 적합하지 않다.
메서드
- before(), beforeName()
이 설정 클래스가 SpringBoot 에 적용되기 전에 적용되어서는 안되는 AutoCongifuration 클래스들이다. 이름 혹은 클래스 이름을 명시적으로 전달할 수 있다.
- after(), afterName()
이 설정 클래스가 SpringBoot 에 적용되기 전에 적용되어 있어야하는 AutoCongifuration 클래스들이다. 이름 혹은 클래스 이름을 명시적으로 전달할 수 있다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {
@AliasFor(annotation = Configuration.class)
String value() default "";
@AliasFor(annotation = AutoConfigureBefore.class, attribute = "value")
Class<?>[] before() default {};
@AliasFor(annotation = AutoConfigureBefore.class, attribute = "name")
String[] beforeName() default {};
@AliasFor(annotation = AutoConfigureAfter.class, attribute = "value")
Class<?>[] after() default {};
@AliasFor(annotation = AutoConfigureAfter.class, attribute = "name")
String[] afterName() default {};
}
2. @AutoConfigurationBefore, @AutoConfigurationAfter
@EnableAutoConfiguration 에 대한 힌트를 제공하는 어노테이션들이다. '자동 설정' 등록된 Bean 들이 특정 Configuration 보다 먼저, 특정 Configuration 이후에 '적용' 되어야 함을 나타낸다.
이때 어노테이션을 살펴보면서 Bean 의 '적용' 과 '생성(초기화)' 를 분리해서 생각해야 한다. 이 어노테이션들을 통해 '자동설정'의 전후 관계를 맺어주는것은 Bean 이 '적용' 되는 순서에만 영향을 줄 뿐, Bean 이 '생성(초기회)' 되는 순서는 여전히 Bean 들간의 의존관계 그리고 @DependOn 어노테이션에 의해 결정된다.
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
public @interface AutoConfigureBefore {
Class<?>[] value() default {};
String[] name() default {};
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
public @interface AutoConfigureAfter {
Class<?>[] value() default {};
String[] name() default {};
}
3. @ConditionalOnClass, @ConditionalOnMissingBean
ConditionalOnClass : 특정 클래스가 'class path' 에 존재할때 제한적으로 Configuraiton 이 동작하도록 한다.
ConditionalOnMissingBean: 특정 Bean 이 등록되어 있지 않을때 제한적으로 Configuraiton 이 동작하도록 한다.
* class path 는 어디인가?
SpringBoot 로 개발을 하다보면 class path 라는 말을 참 많이 듣는다. 어떨때는 환경변수 세팅 (applicaiton.properties, application.yml 등) 에 대한 레퍼런스를 볼때, 어떨때는 외부 라이브러리에 대한 레퍼런스를 볼때 등장하는 단어이다.
- 소스코드가 컴파일된 결과(build/classes/java/main) 의 위치를 class path 라고 부르기도 한다.
- 그리고 역시 src/main/resources 역시 class path 라고 부른다.
- 또한 외부 라이브러리를 읽어왔을때 해당 .jar 파일의 위치도 class path 라고 부른다.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
// --------
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
Class<?>[] value() default {};
String[] type() default {};
Class<?>[] ignored() default {};
String[] ignoredType() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
실무에서 AuthoConfiguration
지금까지 '자동설정' 에 대한 어노테이션들을 알아봤다. 물론 모두 알아본건 아니고 일부만 알아봤지만 대략적인 그림은 나온것 같다.
그렇다면 이렇게 '자동설정' 으로 표시된 Bean 들은 언제 나타나는 걸까?
Spring Initializer 로 Web 의존성만 부여하고 @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 {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class,attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class,attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = ComponentScan.class,attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
다음의 두 가지 어노테이션이 눈에 띈다.
- @ComponentScan
- @EnableAutoConfiguration
1. @CompoentScan
지정된 경로(SpringBootApplication 이하의 모든 경로) 의 @Compoent 들을 Spring IoC Container 가 scanner 하여 관리할 수 있도록 해준다. 우리는 이 어노테이션을 통해 @Configuration, @Controller, @Service, @Repository, @Compoent 를 정의하고 Spring IoC Container 에게 관리를 일임할 수 있었다.
그런데 이것만 있다면 SpringIoC Container 는 Dispatcher Servlet,HttpMessageConverter 등은 어떻게 검색하고 초기화할 수 있었을까? 그에 대한 해답이 다음의 @EnableAutoConfiguration 인 것이다.
2. @EnableAutoConfiguration
Spring 애플리케이션 컨텍스트의 자동 구성을 활성화한다. 이때 '개발자가 필요로 하는 빈을 추측하고' 설정한다. 이때 추측한다는 것은 @ConditionalOnClass, @ConditionalOnMissingBean 을 활용한 로직이 동작하는 것으로 생각된다.
Spring 프레임워크는 이렇게 '자동설정' 구성을 통해 우리가 필요로 하는 기능을 구현해주고 있다는걸 알게 되었다
'탐구 생활 > SpringBoot 파헤치기' 카테고리의 다른 글
Spring 트랜잭션 파헤치기 (2) TransactionInterceptor (0) | 2024.10.29 |
---|