동적이라는 것은
내가 어떤 configuration을 가져올지를 db에서 읽어와서 참고할 수도 있고 외부 설정파일로도 가져올 수 있다. 코드에 의해
EnableMyAutoConfiguration을 고치지 않아도 되어야 한다는 것이다.
동적으로 가져올 때는 @import 로는 부족하다.
ImportSelector 라는 interface를 살펴보자.
annotation이라는 meta data를 받고 return을 String[] 에다가 클래스 이름을 넣어서 주면 된다.
ImportSelector를 확장헌 DefferedImportSelector를 사용할 것이다.
Import가 가져오는 것은 Configuration 클래스인데
특별히 ImportSelector 인터페이스를 구현한 클래스를 가져오면
그 안에 있는 메서드를 실행해서 결과로 돌아오는 String 값에 해당하는 클래스만 로딩하도록 해줌.
이것을 이용하면 Configuration을 조금 더 자유롭게 들고오도록 할 수 있다.
변경 전과 변경 후를 비교해보자.
변경
package com.example.config;
import com.example.config.autoconfig.DispatcherServletConfig;
import com.example.config.autoconfig.TomcatWebServerConfig;
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;
@Retention(RetentionPolicy.RUNTIME)
// type : class, interface, enum을 대상으로 부여
@Target(ElementType.TYPE)
@Import({DispatcherServletConfig.class, TomcatWebServerConfig.class})
public @interface EnableMyAutoConfiguration {
}
변경 후
package com.example.config;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyAutoConfigImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
"com.example.config.autoconfig.DispatcherServletConfig",
"com.example.config.autoconfig.TomcatWebServerConfig",
};
}
}
package com.example.config;
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;
@Retention(RetentionPolicy.RUNTIME)
// type : class, interface, enum을 대상으로 부여
@Target(ElementType.TYPE)
@Import(MyAutoConfigImportSelector.class)
public @interface EnableMyAutoConfiguration {
}
아직 문자열로 박혀있기 때문에
완전 동적으로 바뀌었다고 볼 수는 없다.
조금 더 동적으로 변경해보자.
외부 파일에서 configuration 정보를 읽어오도록 수정해보자
package com.example.config;
import org.springframework.boot.context.annotation.ImportCandidates;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.StreamSupport;
public class MyAutoConfigImportSelector implements DeferredImportSelector {
private final ClassLoader classLoader;
public MyAutoConfigImportSelector(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 자동 구성 대상 후보들을 읽어온다.
// 우리가 어떤 어플리케이션의 클래스 패스에서 resource, file들을 읽어올때 classLoader를 사용한다.
// 파일에다가 설정해둘 configuration 목록들이 들어가 있을 것이다.
// Iterable<String> candidates = ImportCandidates.load(MyAutoConfiguration.class, classLoader);
// return StreamSupport.stream(candidates.spliterator(), false).toArray(String[]::new);
// 변경1
List<String> autoConfigs = new ArrayList<>();
/*for (String candidate : ImportCandidates.load(MyAutoConfiguration.class, classLoader)) {
autoConfigs.add(candidate);
}*/
// 변경2
/*ImportCandidates.load(MyAutoConfiguration.class, classLoader).forEach(candidate ->
autoConfigs.add(candidate)
);*/
// 변경 3
ImportCandidates.load(MyAutoConfiguration.class, classLoader).forEach(autoConfigs::add);
return autoConfigs.toArray(new String[0]);
// return autoConfigs.toArray(String[]::new);
// return Arrays.copyOf(autoConfigs.toArray(), autoConfigs.size(), String[].class)
// 이중에서 어떤 것이 사용되게 할 것인지는 스마트한 방법으로 결정을 할 것이다.
}
}
어떤 파일에서 정보를 읽어오냐면
ImportCandidates 클래스의 load라는 메서드에서 설명을 읽어보면 된다.
META-INF/spring/full-qualified-annotation-name (패키지 이름까지 포함한 이름)
com.example.config.autoConfig.DispatcherServletConfig
com.example.config.autoConfig.TomcatWebServletConfig
'강의 > 토비의 스프링부트' 카테고리의 다른 글
@Configuration과 proxyBeanMethods (0) | 2023.02.23 |
---|---|
자동 구성 애노테이션 적용 (0) | 2023.02.23 |
자동 구성 기반 애플리케이션 (meta annotation, composed annotation) (0) | 2023.02.23 |
ㅇㄹㄴㅇ (0) | 2023.02.22 |
테스트 코드 (0) | 2023.02.22 |