스프링 부트를 사용하면 DataSource, DriverManager 등 빈 등록을 하지 않아도 사용이 가능하다.
이는 스프링 부트가 자동 구성 (Auto Configuration)이라는 기능을 지원하기 때문인데, 이는 자주 사용하는 빈들을 자동으로 등록해준다.
따라서 반복적이고 복잡한 빈 등록, 설정을 최소화시켜 준다.
그렇다면 Auto Configuration이 어떻게 동작하는지 알아보도록 하겠다.
Auto Configuration 동작 방식
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
먼저 스프링 부트 메인 클래스에서 @SpringBootApplication 애노테이션 내부를 살펴보면 @EnableAutoConfiguration 이라는 애노테이션이 존재한다.
해당 애노테이션은 자동 구성을 활성화하기 위한 애노테이션이며, 내부를 살펴보면 다음과 같다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
여기서 @Import는 주로 스프링 설정 정보(@Configuration)를 포함할 때 사용하는데, AutoConfigurationImportSelector의 경우 @Configuration이 아니다.
@Import에서 설정 정보를 추가하는 방법을 2가지이다.
- @Import(클래스) : 정적
- @Import(ImportSelector) 설정 대상을 동적으로 지정
- 예를 들어 다음과 같은 설정 정보가 있다고 하자.
@Configuration
public class HelloConfig {
@Bean
public HelloBean helloBean() {
return new HelloBean();
}
}
public class HelloImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"hello.selector.HelloConfig"};
}
}
그리고 ImportSelector 인터페이스를 구현한 HelloImportSelector는 hello.selector.HelloConfig 설정 정보를 반환하도록 한다.
마지막으로 스프링 컨테이너를 생성하고 @Import(HelloImportSelector.class)를 초기 설정 정보로 사용해서 Configuration을 만들면 스프링은 HelloImportSelector.selectImports()를 실행하고 hello.selector.HelloConfig를 반환받아 이를 설정 정보로 사용한다.
@Test
void selectorConfig() {
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(SelectorConfig.class);
HelloBean bean = appContext.getBean(HelloBean.class);
assertThat(bean).isNotNull();
}
@Configuration
@Import(HelloImportSelector.class)
public static class SelectorConfig {
}
스프링 부트는 resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 경로의 파일에 수많은 문자열들이 존재하고 이를 읽어서 설정 정보로 사용한다.
spring-boot-autoconfigure 의존성에서 해당 파일을 확인할 수 있다.
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
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
...
따라서 스프링 부트는 위에서 수많은 XxxAutoConfiguration을 자동으로 등록하는데 그 중 DataSource를 설정하는 자동 구성을 확인하면 다음과 같다.
@AutoConfiguration(
before = {SqlInitializationAutoConfiguration.class}
)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
type = {"io.r2dbc.spi.ConnectionFactory"}
)
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({DataSourcePoolMetadataProvidersConfiguration.class})
public class DataSourceAutoConfiguration {
public DataSourceAutoConfiguration() {
}
...
}
여기서 @AutoConfiguration은 자동 구성을 할 때 필요한 애노테이션이다.
해당 애노테이션 내부에는 @Configuration이 존재하여 빈을 등록하는 자바 설정 파일로도 사용 가능하다.
스프링 부트를 실행하면 @EnableAutoConfiguration 애노테이션에 의해 @AutoConfiguration이 붙은 모든 클래스를 스캔하고 필터링하여 자동 구성을 활성화한다.
여기서 필터링은 @ConditionalXxx 애노테이션에 의해 이루어지는데 DataSource의 경우 DataSource.class, EmbeddedDatabaseType.class가 있고 R2DBC 타입의 빈이 존재하지 않는 경우 활성화된다는 의미이다.
@Import는 스프링에서 자바 설정을 추가할 때 사용하는 애노테이션이다.
즉 개발자가 직접 빈을 등록한다면 자동 구성이 되지않도록 하고, 자동 구성을 하는데 필요한 의존성이 classPath에 등록되면 활성화가 되도록 하는 것이다.
스프링 부트가 제공하는 @Conditional 애노테이션 종류는 다음과 같다.
→ Condition 인터페이스의 구현체들
- @ConditionalOnClass , @ConditionalOnMissingClass
- 클래스가 있을 때 동작, 없을 때 동작
- @ConditionalOnBean, @ConditionalOnMissingBean
- 빈이 등록되어 있을 때 동작, 없을 때 동작
- @ConditionalOnProperty
- 환경 정보가 있을 때 동작
- @ConditionalOnResource
- 리소스가 있을 때 동작
- @ConditionalOnWebApplication, @ConditionalOnNotWebApplication
- 웹 애플리케이션 일 때 동작, 아닐 때 동작
- @ConditionalOnExpression
- SpEL 표현식을 만족하는 경우 동작
정리하면 다음과 같다.
- 스프링 부트 메인 클래스 실행. (@SpringBootApplication)
- @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector.class)
- resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에서 설정 정보 선택
- 해당 파일의 설정 정보 중에서 @AutoConfiguration가 붙은 클래스들을 조회
- 해당 클래스들 중에서 Conditional 조건에 부합하는 클래스를 스프링 컨테이너에 빈으로 등록
@AutoConfiguration 도 설정 파일로 내부에 @Configuration 이 있지만 일반 스프링 설정과 라이프사이클이 다르므로 컴포넌트 스캔의 대상이 되면 안되고 파일에 지정해서 사용해야 한다.
(resources/META-INF/spring/ org.springframework.boot.autoconfigure.AutoConfiguration.imports)
스프링 부트는 실행 시 AutoConfigurationExcludeFilter 필터를 통해 @AutoConfiguration을 컴포넌트 스캔 대상에서 제외함.
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
참고
스프링 부트 - 핵심 원리와 활용 강의 | 김영한 - 인프런
김영한 | 실무에 필요한 스프링 부트는 이 강의 하나로 모두 정리해드립니다., 백엔드 개발자를 위한 스프링 부트 끝판왕! 실무에 필요한 내용을 모두 담았습니다. [임베딩 영상] 김영한의 스
www.inflearn.com
'Spring' 카테고리의 다른 글
[Spring] OAuth2.0을 이용한 네이버, 구글 소셜 로그인 구현 (0) | 2025.01.02 |
---|---|
[Spring] 외부 설정, @Profile (0) | 2024.12.28 |
[Spring-boot] JAR, WAR (0) | 2024.12.28 |
[Spring AOP] @Aspect AOP (0) | 2024.12.28 |
[Spring AOP] 스프링 AOP와 용어 (0) | 2024.12.28 |