[spring] SpringBoot의 AutoConfiguration 동작방식

2022. 4. 25. 13:58[ 백엔드 개발 ]/[ Spring ]

스프링 프레임워크와 스프링 부트의 차이점 중 하나는 AutoConfiguration의 기능으로 알고 있었지만, 이 기능이 어떤 방식으로 동작하는지 궁금했고 이번 기회에 스프링 부트의 AutoConfiguration의 동작 과정에 대해 포스팅해보았다.

 

본론으로 들어가기 앞서 Spring과 Spring Boot의 차이점에 대해 알아보자.

 

Spring과 Spring Boot의 가장 큰 차이점은 '의존성의 버전 관리'와 '간편한 자동 설정'이다.

 

Spring

- 필요한 dependency를 모두 직접 빌드 툴에 등록해줘야 한다.

- Dependency의 버전을 직접 명시해줘야 한다.

- 필요한 설정 파일을 작성하고 빈으로 등록해야 한다.

 

Spring Boot

- 필요한 dependency의 묶음을 제공하고 추가적으로 직접 버전을 명시하지 않아도 '권장 버전'으로 맞춰준다.

- 여기서 버전을 제공해준다는 점이 중요한데 Spring 같은 경우에는 서로 의존하는 모듈들끼리의 버전이 호환되도록 맞춰주어야 했다. 하지만 Spring Boot에서 제공하는 모듈을 사용하면 관련 Depdenecy들의 서로 호환되는 버전을 자동으로 맞춰서 제공한다.

- 버전 관리 외에도 설정 파일을 직접 만들지 않아도 된다는 장점이 있다. Spring의 경우 @Configuration 파일을 빈으로 등록하고 직접 설정 값들을 하나씩 입력해 줘야 했지만 Spring Boot에서는 기본적인 설정들을 제공한다. 또한 추가적으로 설정할 정보들이 있다면 @Configuration 파일을 빈으로 등록하지 않고도 application.properties/yml/yaml 등의 파일을 통해 손쉽게 설정할 수 있다. 특히 yml 파일을 활용하면 가독성 좋은 설정 파일을 작성할 수 있다.

- 이러한 자동 설정은 Spring Boot에서 제공하는 starter 패키지에서 제공되는데, starter 패키지에는 XXXProperties라는 클래스가 추가적으로 들어간다. 해당 클래스에는 기본적인 설정 정보를 포함하고 있고 따라서 따로 설정 파일을 빈으로 등록하지 않아도 간편하게 의존성을 사용할 수 있게 되는 것이다.

 

 

위 사진은 spring-boot-starter-thymeleaf 의존성에 포함되는 ThymeleafProperties 클래스이다. 해당 파일을 보면 기본적으로 여러 가지 설정 정보를 제공하고 있음을 알 수 있다. 이러한 Spring Boot의 자동 설정 패키지 덕분에 웹서버, WAS 또한 내장시켜 애플리케이션을 구동할 수 있다. 또한 웹 서버에 대한 설정 정보를 yml 파일을 통해 간단하게 설정할 수 있게 되었다.

 


SpringBoot의 AutoConfiguration 동작 방식

우선 스프링 부트는 @SpringBootApplication 어노테이션 기반으로 동작한다. 이 어노테이션은 main 메소드가 있는 클래스에 등록해주어야 애플리케이션이 로딩될 때 스프링 부트 기반으로 동작한다.

 

 

아래와 같이 @SpringBootApplication 어노테이션을 살펴본 결과 @EnableAutoConfiguration 어노테이션을 확인할 수 있었다. 그리고 @EnableAutoConfiguration을 들어가 본 결과는 아래와 같다.

 

 

 

해당 어노테이션의 설명을 요약하자면, 개발자가 등록한 bean(예를 들면 tomcat, data-jpa, data-mongodb 등)에 대한 설정과 이와 연관된 bean들을 모두 설정해준다. 예를 들어 데이터베이스 connection pool에 대한 설정 등을 개발자가 설정 파일에 등록해주면 이들을 읽어 알아서 bean에 주입한다. 만약 설정 파일을 작성하지 않았다면 deafault 설정을 주입한다.

 

뿐만 아니라 AutoConfiguration은 개발자가 등록하지 않은 bean들(예를 들면 스프링 부트에서 제공하는 Starter 패키지에 정의된 bean)도 classpath 아래를 기준으로 component-scan을 통해 찾고 bean으로 등록한다. 

 

 

@EnableAutoConfiguration 에는 AutoConfigurationImportSelector를 Import 하고 있는데 AutoConfigurationImportSelector는 Auto Configuration 할 클래스들을 선택적으로 적용될 수 있도록 해준다.

 

 

AutoConfigurationImportSelector

AutoConfigurationImportSelectordml의 getAutoConfigurationEntry() 메소드에서 Auto Configuration 될 엔트리들이 만들어지고 있음을 확인할 수 있다.

 

 

cf. 디버깅해서 확인해보기

 

 

getAutoConfigurationEntry() 메소드에서 getCandidateConfigurations()를 통해 configuration 후보군들을 가져온다. 후보군을 대략적으로 살펴보면 대표적으로, 데이터베이스 커넥션 풀을 위한 AutoConfiguration과 application 설정 파일을 읽어 bean에 주입해주는 AutoConfiguration class 등을 확인할 수 있다.

 

 

getAutoConfigurationEntry() 메소드의 로직을 살펴보면 @EnableAutoConfiguration 어노테이션의 인자로 제외할 AutoConfiguration class를 설정할 수 있는데 해당 값을 getAutoConfigurationEntry() 메소드에서 제외하며 그 후에는 filter를 통해 제외할 configuration들을 걸러낸다.

 

 

AutoConfiguration 후보군을 읽어오는 위치

 

/META-INF/spring.factories

 

AutoConfiguration 할 클래스들의 목록은 spring-boot-autoconfiguration 모듈의 META-INF/spring.factories 파일에 있다. 스프링 애플리케이션이 시작될 때 해당 파일을 모두 읽어 Auto Configuration의 후보군으로 올린다. 그 뒤, exclude 할 class와 filter 조건을 보면서 실제로 주입할 설정 정보를 결정한다.

 

해당 파일의 구조는 key-value 구조로 되어 있으며 Key는 인터페이스이고 value에는 해당 인터페이스에 대한 AutoConfiguration 목록들임을 확인할 수 있다.

 

각 AutoConfiguration클래스는 Conditional 어노테이션이 달려 있는데 해당 어노테이션은 스프링 부트가 아닌 스프링 프레임워크에서 지원하며 해당하는 Condition에 filter를 넣어 해당 설정이 로드될지 말지를 결정한다.

 

예시

 

 

예를 들어 JdbcTemplate을 사용할 경우(JdbcTemplate도 bean이다) 이와 관련된 AutoConfiguration 클래스는 JdbcTemplateAutoConfiguration이다. 위와 같이 JdbcTemplateAutoConfiguration을 보면 @ConditionalOnClass가 있는데, 이 어노테이션은 JdbcTemplate과 DataSource가 클래스 패스 상에 존재해야지만 filter에 걸리지 않고 AutoConfiguration 될 수 있도록 한다는 의미이다.

 

즉, JdbcTemplate이 gradle 디펜던시 설정에 등록되어 있다면 컨디셔널 어노테이션에 따라 자동 설정이 주입된다. 해당 의존성이 gradle 설정에 없다면 filter(커디 셔널 어노테이션에 지정된)에서 걸려서 설정이 주입되지 않을 것이다.

 

 

스프링 부트에서 제공되는 컨디션(filter조건) 정보 확인하기 : https://reflectoring.io/spring-boot-conditionals/

 

 


 

@EnableConfigurationProperties

클래스 패스 하에 있는 application 설정 파일을 자동으로 읽어 bean에 주입해주는 AutoConfiguration 중 일종이다.

 

 

cf. JDBC 설정에 대한 예시

 

위와 같이 설정 파일의 prefix를 읽어 configuration 빈을 생성할 때 자동으로 주입한다.

 

 

위와 같이 properties를 읽어서 JdbcTemplate을 생성할 때 해당 정보들을 넣어주고 있음을 확인할 수 있다.

 

 

위와 같이 스프링 부트의 핵심은 AutoConfiguration이며 이로써 개발자는 비즈니스 로직에 더욱 집중할 수 있게 된다. 스프링 부트에서 제공하는 starter 모듈을 사용하면 이러한 AutoConfiguration 기능을 사용할 수 있을 뿐만 아니라 해당 모듈과 관련된 모듈들과 호환되는 버전을 맞춰 하나의 패키지로 제공한다. 

 

 

회고

스프링(부트) 프레임워크가 제공해주는 기능이 정말 막강한 것 같다. 코드를 아름답게 짜는 것도 좋지만, 그전에 선행되어야 할 것은 기술의 원리를 제대로 파악하는 것이라 생각한다.