2024. 10. 17. 16:20ㆍSpring Boot/Spring Boot Auto Configuration
DeferredImportSelector는 Spring Framework에서 구성 클래스를 동적으로 로딩하는 인터페이스인 ImportSelector를 확장한 인터페이스로, 일반 ImportSelector보다 더 나중에 실행되어 구성 클래스를 로딩할 수 있습니다. DeferredImportSelector는 스프링 컨텍스트가 초기화되는 과정에서 다른 빈이나 구성이 먼저 처리된 후에 실행됩니다. 이 특성 때문에 주로 프레임워크 확장, 모듈화된 구성, 또는 복잡한 로딩 순서가 필요한 경우에 사용됩니다.
주요 개념 및 사용 목적
- ImportSelector는 구성 클래스를 동적으로 로드하는 기능을 제공합니다.
- DeferredImportSelector는 '지연된(Deferred)' 방식으로 ImportSelector보다 나중에 실행되며, 다른 ImportSelector와 빈 정의들이 모두 처리된 후에 실행됩니다.
언제 사용하나?
DeferredImportSelector는 특정 모듈이나 구성 클래스가 스프링 컨텍스트에 등록된 후에 추가적인 구성을 적용하거나 동적으로 빈을 추가하고 싶을 때 유용합니다. 이는 다음과 같은 경우에 많이 사용됩니다:
- 모듈간 의존성 관리: 여러 모듈이 상호 의존적일 때, 일부 모듈의 구성이 먼저 적용된 후에 다른 설정이 필요할 때 사용됩니다.
- 프레임워크 확장: Spring Security, Spring Cloud 등의 프레임워크에서 구성이 복잡할 때, 구성 순서를 제어하고 여러 구성을 결합해야 할 때 유용합니다.
- 클래스 로딩 순서 제어: 다른 ImportSelector들이 로드한 클래스나 빈을 기반으로 추가 구 클래스를 로드할 필요가 있을 때 사용할 수 있습니다.
DeferredImportSelector의 메서드
1. selectImports(AnnotationMetadata importingClassMetadata):
- ImportSelector와 동일하게 설정 클래스의 전체 이름을 반환합니다. 스프링 컨텍스트에 동적으로 로드할 설정 클래스의 목록을 반환하는 역할을 합니다.
String[] selectImports(AnnotationMetadata importingClassMetadata);
2. getImportGroup() : 선택사항
- DeferredImportSelector.Group 인터페이스를 구현하는 클래스를 리턴할 수 있습니다. 이 메서드를 통해 여러 DeferredImportSelector가 그룹화되어 실행 순서를 조정하거나, 그룹 단위로 구성을 적용할 수 있습니다.
Class<? extends DeferredImportSelector.Group> getImportGroup();
DeferredImportSelector.Group 인터페이스
DeferredImportSelector.Group 인터페이스는 여러 DeferredImportSelector를 그룹화하여 하나의 단위로 처리할 수 있게 해주는 기능을 제공합니다. 이 인터페이스는 다음과 같은 메서드를 가지고 있습니다:
1. process(AnnotationMetadata metadata, DeferredImportSelector selector)
- 각 DeferredImportSelector의 애노테이션 메타데이터와 선택된 설정 클래스를 처리하는 역할을 합니다.
void process(AnnotationMetadata metadata, DeferredImportSelector selector);
2. selectImports()
- 최종적으로 로드할 설정 클래스들의 리스트를 반환합니다. 이를 통해 여러 DeferredImportSelector가 하나의 단위로 처리됩니다.
Iterable<DeferredImportSelector.Group.Entry> selectImports();
Group 인터페이스를 통해 여러 개의 DeferredImportSelector를 그룹으로 묶고, 구성 로딩 순서를 제어할 수 있습니다.
DeferredImportSelector 사용 예시
아래 예시는 특정 조건에 따라 설정 클래스를 나중에 로딩하는 DeferredImportSelector를 구현한 예제입니다.
DeferredImportSelector.java
package com.example.selector;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyDeferredImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
"com.example.config.DeferredConfig"
};
}
@Override
public Class<? extends Group> getImportGroup() {
return MyDeferredImportGroup.class;
}
public static class MyDeferredImportGroup implements Group {
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
// 필요한 로직을 여기에 처리
}
@Override
public Iterable<Entry> selectImports() {
// 로드할 설정 클래스를 반환
return List.of(new Entry(AnnotationMetadata.introspect(DelayedConfig.class)));
}
}
}
AppConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public String initialBean() {
return "Initial Bean Loaded";
}
}
DeferredConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DeferredConfig {
@Bean
public String deferredService() {
return "Deferred Service Bean Loaded";
}
}
@EnableMyFeature.java
import com.example.selector.MyDeferredImportSelector;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyDeferredImportSelector.class)
public @interface EnableMyFeature {
}
DefferredImportApplication.java
package com.example;
import com.example.annotation.EnableMyFeature;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
@EnableMyFeature // DeferredImportSelector가 적용됨
public class MyApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MyApplication.class, args);
// 기본 설정 클래스에서 로드된 빈 출력
if (context.containsBean("initialBean")) {
System.out.println(context.getBean("initialBean"));
} else {
System.out.println("Initial bean was not loaded.");
}
// 지연 로딩된 빈 출력
if (context.containsBean("deferredBean")) {
System.out.println(context.getBean("deferredBean"));
} else {
System.out.println("Deferred bean was not loaded.");
}
}
}
동작 설명
- AppConfig의 빈 로드: AppConfig는 일반적인 스프링 설정 클래스입니다. 이 클래스는 애플리케이션 시작 시 즉시 로드되며, initialBean이 등록됩니다.
- DeferredConfig의 지연 로딩: MyDeferredImportSelector는 모든 다른 빈 정의가 끝난 후에 실행됩니다. 즉, AppConfig에서 정의된 빈이 모두 처리된 후에 DeferredConfig에서 정의된 deferredBean이 등록됩니다.
- 실행 흐름: 스프링 애플리케이션이 실행되면 먼저 AppConfig에서 빈이 등록되고, 그 다음에 DeferredConfig가 지연 로딩되어 deferredBean이 등록됩니다.
실행 결과
애플리케이션을 실행하면 다음과 같은 출력이 나타납니다:
Initial Bean Loaded
Deferred Bean Loaded
이 출력은 스프링 애플리케이션에서 DeferredImportSelector가 지연 로딩되는 방식으로 설정 클래스를 처리하는 과정을 보여줍니다.
요약
- DeferredImportSelector는 설정 클래스가 나중에 로드되도록 하여, 다른 빈이 모두 등록된 후에 특정 설정이나 빈을 추가하는 데 사용됩니다.
- 이 예제에서는 AppConfig에서 빈이 먼저 로드되고, DeferredConfig가 나중에 로드되는 시나리오를 보여주었습니다.
'Spring Boot > Spring Boot Auto Configuration' 카테고리의 다른 글
AnnotationConfigServletWebServerApplicationContext (0) | 2024.10.18 |
---|---|
AutoConfigurationImportSelector (0) | 2024.10.18 |
spring-boot-autoconfigure.jar (0) | 2024.10.16 |
spring.factories (0) | 2024.10.16 |
Project Classpath (0) | 2024.10.16 |