[SpringBoot] 자동환경설정::AutoConfiguration 까보기

adam2·2020년 4월 8일
2

자바를자바라

목록 보기
4/5

자동 환경 설정은 스프링 부트의 가장 큰 장점이라고 생각한다.

스프링부트는 web, h2, jdbc등등 약 100여가지의 자동 설정(starter)을 제공한다.

새로 추가되는 라이브러리(jar)는 스프링부트 자동설정 의존성에 따라 설정이 자동 적용된다.

ex) h2의존성이 클래스 경로에 존재하면 자동으로 인메모리 데이터베이스에 접근한다.

이런 자동 환경설정 기능은 기존의 스프링에서 의존성 버전 맞추기 지옥을 해결해 줄 수 있다.

스프링부트에서는 @EnableAutoConfiguration 또는 @SpringBootApplication 중 하나만 사용하면 자동 환경설정이 가능하다!!

@SpringBootApplication = (@Configuration + @EnableAutoConfiguration + @ComponentScan)

🔆@EnableAutoConfiguration은 @Configuration 과 함께 사용해야 한다.

start에 있는 설정이 어떻게 자동으로 적용되는걸까

    // SpringBootApplication.java
    
    @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 내부 로직을 보면 @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan 을 래핑해 놓은 것을 볼 수 있다.

  • @SpringBootConfiguration: 스프링 부트의 설정을 나타내는 어노테이션이다. 스프링의 @Configuration을 대체하며 스프링 부트 전용 어노테이션이다. 테스트 어노테이션을 사용할 때 계속 이 어노테이션을 찾기 때문에 스프링 부트에서는 필수 어노테이션이다.
  • @EnableAutoConfiguration: 자동 설정의 핵심 어노테이션이다. 클래스 경로에 지정된 내용을 기반으로 설정 자동화를 수행한다.
  • @ComponentScan: basePackages 프로퍼티 값에 별도의 경로를 설정하지 않으면 해당 어노테이션이 위치한 패키지가 루트 경로가 된다.

그 다음은 EnableAutoConfiguration 어노테이션의 내부를 살펴보자.

    // EnableAutoConfiguration.java
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
       ...
    }

이중 자동 설정을 지원해주는 어노테이션은 @Import 어노테이션이다.

AutoConfigurationImportSelector 클래스를 import하고 있는데 이 클래스 내부도 살펴보자.

    ...
    
    		// 1.
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            } else {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
                return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
            }
        }
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
            if (!this.isEnabled(annotationMetadata)) {
                return EMPTY_ENTRY;
            } else {
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // 2.
    						List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                // 3.
    						configurations = this.removeDuplicates(configurations);
    						Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
    						// 3.
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
            }
        }
    ...
  1. selectImports() 메서드가 자동 설정할 빈을 결정한다.

  2. 모든 후보빈을 getCandidateConfigurations() 메서드를 사용해 불러온다.

    META-INF/spring.factories 에 정의된 자동 설정할 클래스들을 먼저 불러온다.

  3. starter를 여러개 등록하면 중복 빈이 설정 될 경우가 많기 때문에 이런 경우 제외할 설정(getExclusions())과 중복된 설정(removeDuplicates())을 제외시켜준다.

빈의 등록과 자동 설정에 필요한 파일

  • META-INF/spring.factories
    • 자동 설정 타깃 클래스 목록
    • 이곳에 선언된 클래스들이 @EnableConfiguration 사용 시 자동 설정 타깃이 된다.
  • META-INF/spring-configuration-matadata.json
    • 자동 설정에 사용할 프로퍼티 정의 파일
    • 미리 구현되어 있는 자동 설정에 프로퍼티만 주입시켜주면 된다.
    • 변경을 위해서는 application.properties 나 application.yml에 프로퍼티 값을 추가한다.
  • org/springframework/boot/autoconfigure
    • 미리 구현해놓은 자동 설정 리스트
    • 모두 자바 설정 방식을 따른다.

📣정리

@EnableAutoConfiguration 어노테이션에서 AutoConfigurationImportSelector 클래스를 import하는데, AutoConfigurationImportSelector 클래스는 자동설정할 후보빈을 불러오고 제외하거나 중복된 설정들을 제외하는 등의 작업을 거친 후 자동 설정할 빈을 결정하는 역할을 한다.

@EnableAutoConfiguration 어노테이션을 선언하면 빈의 등록과 자동 설정이 가능하고, @SpringBootApplication 어노테이션은 @EnableAutoConfiguration 어노테이션을 래핑하고 있다.

따라서 @SpringBootApplication 또는 @EnableAutoConfiguration 어노테이션을 사용하면 자동 환경설정 기능을 사용할 수 있는 것이다.

스프링 부트의 자동 설정 어노테이션

스프링 부트는 자동 설정이 적용되는 조건, 시점 등에 따라 다양한 어노테이션을 지원하기 때문에 설정 환경을 쉽게 커스터마이즈 할 수 있다.

어노테이션설명
@ConditionlOnBean해당하는 빈 클래스나 이름이 미리 빈 팩토리에 포함되어 있을 경우
@ConditionalOnClass해당하는 클래스가 클래스 경로에 있을 경우
@ConditionalOnCloudPlatform해당하는 클라우드 플랫폼이 활용 상태인 경우
@ConditionalOnExpressSpEL에 의존하는 조건일 경우

0개의 댓글