Spring Boot AutoConfiguration 자동 설정, 원리
- Spring Boot는 Spring과 마찬가지로 component-scan을 통해서 component들을 찾아서 bean을 생성한다.
- 이 과정으로 설정한 bean들(
@Repository, @Service, @Controller, @RestController, @Configuration
에 등록한@Bean
과 같은 설정들)이 생성된다 - Spring Boot에서 미리 작성된 autoconfiguration에 의해 추가적인 bean들도 같이 생성된다.
@SpringBootApplication
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}
아래와 같다
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}
}
@SpringBootApplication
에는@ComponentScan
과@EnableAutoConfiguration
을 포함하고 있다
@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 {
//요약
}
@EnableAutoConfiguration
- Spring Boot에서 Spring에서 많이 쓰는 스프링 빈들을 자동적으로 컨테이너에 등록하는 역할
- autoconfiguration기능을 사용하겠다는 설정
- component scan을 통해서 모든 component 들의 정보와 Spring Boot가
spring.factories
파일에 사전에 정의한 AutoConfiguration 내용에 의해 bean 생성이 진행된다. - Spring Boot의 meta 파일(spring-boot-autoconfigure/META-INF/spring.factories)을 읽어서 미리 정의 되어있는 자바 설정 파일(
@Configuration
)들을 빈으로 등록하는 역할을 수행 한다
spring-boot-autoconfigure/META-INF/spring.factories
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
....
이렇게 spring.factories
안에는 여러가지 autoConfiguration들이 정의되어 있다.
이 키값에 설정되어 있는 것들은 모두 autoConfiguration의 대상이되며 적용된다. (단, 조건에 따라서 등록이 안될 수도 있다.)
@ComponentScan
- 해당 패키지에서 @Componont 어노테이션을 가진 Bean들을 스캔해서 등록한다. (@Configuration, @Repository, @Service, @Controller, @RestController)
- @ComponentScan("me.thewing.sample")
- 해당 패키지 하위 모든 패키지를 component scan 범위로 잡겠다는 설정이다 . package 위치를 입력하지 않으면 Application이 있는 패키지가 기본값으로 사용된다.
Auto Configuration Filters , Conditions
- Spring Boot가 미리 정해둔 AutoConfiguration 정보는 위에서 말했듯이
spring.factories
에서 확인이 가능하다 - AutoConfiguration 들은 필요한 상황에만 자신이 실행 될 수 있도록 @Conditional, @Condition 과 같은 annotation들로 설정되어 있다. 그 어노테이션을 기반으로 필터링이 먼저 이뤄지고 필터링이 되지 않은 AutoConfiguration 을 가지고 작업이 진행된다
- @Condition, @Conditional Spring 4.0부터 추가된 어노테이션이고 Spring Boot auto configuration 과정에서 사용되는 다른 어노테이션들도 autoconfigure-condition에서 확인이 가능하다
- @Profile, @Lazy와 같은 Spring 에서 제공하는 다른 어노테이션들도 Spring Boot auto configuration 에 활용이된다.
Condition interface
- 구성 요소를 등록하기 위해 일치해야하는 단일 조건이다
- 빈 정의가 등록되기 직전에 조건을 확인하고 해당 시점에 결정될 수 있는 기준에 따라 등록을 거부할 수 있다.
- 사용 시점
- property나 environment등 조건을 파악할때 사용된다
@Conditional
- 어노테이션으로 조건부 Bean을 스프링 컨테이너에 등록하는 역할을 한다. Condition Interface를 사용하여 특정 조건부로 등록되도록 할 수 있다.
- Conditional을 확장한 어노테이션은
@ConditionalOnMissingBean
,@ConditionalOnBean
,@ConditionalOnClass
등이 있다 - 조건을 지정하기 위한 클래스이다
Auto Configuration Import Filters
- Spring Boot는 spring.factories 정보를 가지고 auto configration을 진행한다
- AutoConfigurationImportFilter 관련 설정이 있으며 아래와 같은 3개의 필터가 적용된 것을 확인할 수 있다
spring.factories
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
//생략
해당 필터들은 AutoConfiguration 이 가진 @Conditional
을 가지고 조건 만족 여부를 체크한다. 그리고 조건이 맞지 않을 경우에 해당 AutoConfiguration 이 동작하지 않도록 제외 시키는 역할을 수행한다
Condition interface의 구현체
SpringBootCondition implement Condition
- Spring Boot와 함께 사용되는 모든 조건 구현의 기초이다. 사용자가 로드된 클래스를 진단하는데 도움이 되는 적절한 로깅을 제공한다
interface ConfigurationCondition implements Condition
-
@Configuration과 함께 사용할 때보다 세밀한 제어를 제공하는 조건입니다. 특정 조건이 구성 단계에 따라 일치 할 때 적응할 수 있습니다. 예를 들어 빈이 이미 등록되었는지 확인하는 조건은 REGISTER_BEAN ConfigurationCondition.ConfigurationPhase 동안에 만 평가되도록 선택할 수 있습니다.
-
org.springframework.boot.autoconfigure.condition.OnBeanCondition
- 특정 bean들의 존재유무를 확인하는 필터이다
- 적용 대상
@ConditionalOnBean
,@ConditionalOnMissingBean
,@ConditionalOnSingleCandidate
-
org.springframework.boot.autoconfigure.condition.OnClassCondition
- 특정 class들의 존재 유무를 확인하는 필터이다
- 적용 대상
@ConditionalOnClass, @ConditionalOnMissingClass
-
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
- WebApplicationContext의 존재 유무를 확인하는 필터이다
- 적용 대상
@ConditionalOnWebApplication
,@ConditionalOnNotWebApplication
@ConditionalOnMissingBean
- @ConditionalOnMissingBean은 특정 bean이 사전에 생성되지 않은 때 조건이 성립한다.
@Bean
과 함께 사용된다면 이미 생성된 bean이 없을 때 해당 bean을 생성한다 - 특정 bean을 생성하도록 설정해놨다면, 일반적으로 AutoConfiguration의 bean생성 순서가 마지막에 온다
- 직접 생성된 bean이 먼저 생성되고 해당 AutoConfiguration은 필터링되어 중복생성되는 상황을 막는다. 해당 bean을 설정하지 않았다면 AutoConfiguration에서는 해당 bean을 자동 생성하게 된다
- ThreadPoolTaskExecutor bean을 생성하는 TaskExecutionAutoConfiguration.java를 예로 들어보자
TaskExecutionAutoConfiguration.java
// 생략
@Configuration(proxyBeanMethods = false)
public class TaskExecutionAutoConfiguration {
/**
* Bean name of the application {@link TaskExecutor}.
*/
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
// 생략
@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
return builder.build();
}
}
@Lazy
가 걸려 있기 때문에 Spring Boot 실행시 생성되지 않고 ThreadPoolTaskExecutor가 필요한 상황에서 bean이 생성이 요청된다. Executor.class
와 같은 class type인 bean이 이미 생성되지 않은 경우에 @ConditionalOnMissiongBean
조건이 만족되고 bean 생성이 진행된다. 즉 , 아래와 같은 Executor bean을 생성하는 설정을 했다면 설정한 bean이 생성되고 TaskExecutionAutoConfiguration에 의해서는 bean이생성 되지 않는다. 반대로 Executor bean등록을 설정하지 않았더라도 필요한 상황이 되면 해당 bean이 생성되게 된다
@Lazy, @Primary
- @Lazy
- 빈들이 등록되고 나중에 등록된다
- getBean 호출 시 빈으로 등록이 된다
- @Primary
- 기본으로 등록되는 빈이다
- 어느 것이 등록되어도
@Primary
가 있는 빈이 항상 등록이 된다 @Primary
를 두개 사용하면 에러난다
AsyncConfigSample.java
//생략
@Configuration
public class AsyncConfigSample {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(2);
taskExecutor.initialize();
return taskExecutor;
}
}
@ConditionalOnBean
- @ConditionalOnBean은 특정 bean이 이미 생성 되어 있을 때만 조건이 성립한다. 작업을 위해 필수적으로 필요한 bean이 미리 생성 되었는지 확인하는 용도로 사용할 수 있다.
@ConditionalOnClass
- @ConditionalOnClass은 classpath에 특정 class가 존재할 때 조건이 성립한다. 작업을 위해 필수적으로 필요한 의존성이 등록되어 있는지 확인하는 용도로 사용할 수 있다.
메소드에 @ConditionalOnClass를 사용하면 Exception이 발생한다
@Configuration
public class TestConfiguration {
@Bean @ConditionalOnClass(TestBean.class)
public TestBean testBean() {
return new TestBean();
}
}
- ClassNotFoundException이 발생한다
@Configuration
public class TestConfiguration {
@Bean
@ConditionalOnClass(Test.class)
public TestBean testBean() {
return new TestBean();
}
}
ArrayStoreException
(TypenotPresentExceptionProxy
) 이 발생한다
왜 Exception이 발생하는지?
ConfigurationClassPostProcessor
Class는@Configuration
어노테이션이 적용된 빈 객체에서@Bean
어노테이션이 적용된 메서드로 부터 빈 객체를 가져와 스프링 컨테이너에 등록하는 역할을한다
ConfigurationClassPostProcessor
ConfigurationClassParser
를 통해 먼저Class
의 생성 여부를@Conditional
어노테이션들을 포함한 특수한 과정을 통해 정의한다- 위 과정을 통과한
Configuration
Class는ConfigurationClassEnhancerConfiguration
를 통해 Enhance라는 ByteCode를 읽어 들이는 과정을 거쳐 Class를 로드하게 된다
Appendices
Disabling Specific Auto-configuration Classes
- 만약 특정 AutoConfiguration을 사용하지 않으려고 하면 아래와 같이 exclude 설정을 하면된다
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;
@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
// 생략
}
참고
'Spring > Spring Boot' 카테고리의 다른 글
Spring Boot의 SSE(Server-Sent Events) Graceful Shutdown 동작 원리 (0) | 2025.01.05 |
---|---|
Spring Boot의 Graceful Shutdown 동작 원리와 구현 과정 (0) | 2024.11.24 |
@Log4j2 vs @Slf4j with log4j2 (0) | 2021.01.22 |