SpringBoot 코드 분석 - 자동설정 어노테이션

2024. 10. 10. 18:47·탐구 생활/SpringBoot 파헤치기

이전 글에서 SprinbBoot 3.3.4 코드를 분석할 순서를 정했다.

spring-boot-autoconfigure:http 를 까보던중 SpringBoot 를 이용해 코드를 쓸때 직접적으로 사용하지 않았던 생소한 어노테이션들이 있어서 우선 이 어노테이션들을 정리한다.

 

그 목록은 다음과 같다.

  1. @AutoConfiguration
  2. @AutoConfigurationBefore, @AutoConfigurationAfter
  3. @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 등) 에 대한 레퍼런스를 볼때, 어떨때는 외부 라이브러리에 대한 레퍼런스를 볼때 등장하는 단어이다.

 

  1. 소스코드가 컴파일된 결과(build/classes/java/main) 의 위치를 class path 라고 부르기도 한다.
  2. 그리고 역시 src/main/resources 역시 class path 라고 부른다.
  3. 또한 외부 라이브러리를 읽어왔을때 해당 .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
'탐구 생활/SpringBoot 파헤치기' 카테고리의 다른 글
  • Spring 트랜잭션 파헤치기 (2) TransactionInterceptor
개발프로브
개발프로브
가볍게, 오랫동안 기록하고 싶은 블로그입니다.
  • 개발프로브
    ProbeHub
    개발프로브
  • 전체
    오늘
    어제
    • 분류 전체보기 (56)
      • 탐구 생활 (47)
        • 개발 탐구 (8)
        • FastAPI CORS (3)
        • FastAPI Log (4)
        • gRPC&Python (4)
        • SpringBoot 파헤치기 (2)
        • Python Monorepo (3)
        • Python 과 zstd (2)
        • Python (4)
        • FastAPI (4)
        • Terraform (8)
        • MSA (0)
        • GraphQL (2)
        • 데이터베이스 (2)
        • 네트워크 (0)
      • 기초 지식 (9)
        • Terraform (2)
        • MSA (5)
        • K8s (2)
  • 블로그 메뉴

    • 링크

      • github
      • stackoverflow
    • 공지사항

    • 인기 글

    • 태그

      MSA
      sqlalchemy
      python arn64
      grpc
      python 불변 객체
      springboot
      PostgreSQL
      python amd64
      spring 트랜잭션
      python graviton
      ORM 성능 최적화
      오블완
      gzip
      Terraform
      RDBMS 성능 최적화
      티스토리챌린지
      brotli
      granian
      ORM 문제
      zstd
      rest vs grpc
      django 성능 개선
      fastapi cors
      백엔드 성능
      python 성능 개선
      ORM 성능
      fastapi logging
      Python
      FastAPI
      java
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.0
    개발프로브
    SpringBoot 코드 분석 - 자동설정 어노테이션
    상단으로

    티스토리툴바