지금은
@EnableMyAutoConfiguration
에 자동 구성정보가하드코딩
되어있습니다.
이것을 동적으로 할당 할 수 있게 변경하겠습니다.
하드코딩은 강한 결합이기때문에 유지보수에 좋지 못하기 때문입니다.
selectImports()
메소드를 통해 메소드의 이름을 String으로 만들고 그 이름을 구성정보로 스프링 컨테이너가 Bean으로 등록합니다.
우리는ImportSelector
를 한번 더 확장한DeferredImportSelector
를 사용할 것입니다.
DeferredImportSelector
는 다른 @Confing
붙은 클래스의 Bean
설정이 끝난 후에 ImportSelector
가 전달받은 구성정보들을 Bean으로 등록합니다.
사실 중요한것은 우리가 DeferredImportSelector
를 사용해서 자동 구성 정보
를 동적
으로 등록한다는 것입니다
// 동적으로 구성정보를 추가합니다.
public class MyAutoConfigImportSelector implements DeferredImportSelector {
private final ClassLoader classLoader;
public MyAutoConfigImportSelector(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> autoConfigs = new ArrayList<>();
for(String candidate : ImportCandidates.load(MyAutoConfiguration.class, classLoader)){
autoConfigs.add(candidate);
}
return autoConfigs.stream().toArray(String[]::new);
}
}
위처럼 클래스를 생성하고나면 @EnableMyAutoConfiguration
에서 @Import(MyAutoConfigImportSelector.class)
로 바꿔주어야 합니다.
자동구성 정보들은 MyAutoConfigImportSelector에서 selectImports()
메소드를 통해 동적으로 할당될 것이기 때문입니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyAutoConfigImportSelector.class)
public @interface EnableMyAutoConfiguration {
}
selectImports
메소드를 통해외부파일
에 String으로 등록된 자동 구성 정보를 읽어와서 import하고있는 어노테이션에 String으로 반환해 줄것입니다.
자동 구성 정보와 관련된 어노테이션
이다! 라는것을 알려주기 위함입니다.
어노테이션을 보고 ~겠구나 라고 짐작하는것은 작지만 서비스가 커질수록 중요한것 같습니다.
다음 글에서는 자동 구성 정보 Bean에 이 어노테이션을 적용할것입니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Configuration
public @interface MyAutoConfiguration {
}
클래스 로더
를 통해 정보를 불러올 수 있습니다.
클래스 로더는 어떤 애플리케이션에 클래스 패스에서 정보를 읽어올때, 클래스 로더를 사용합니다!
그리고 selectImports
메소드를 통해 String 값을 넘기면 됩니다.
// 동적으로 구성정보를 추가합니다.
public class MyAutoConfigImportSelector implements DeferredImportSelector {
private final ClassLoader classLoader;
public MyAutoConfigImportSelector(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> autoConfigs = new ArrayList<>();
for(String candidate : ImportCandidates.load(MyAutoConfiguration.class, classLoader)){
autoConfigs.add(candidate);
}
return autoConfigs.stream().toArray(String[]::new);
}
}
ImportCandidates.
load
를 통해서 String 정보를 읽어옵니다.
아래를 보면 files named META-INF/spring/full-qualified-annotation-name.
에서 정보를 읽는것을 알 수 있습니다.
폴더를 만들고
tobyspring.config.autoconfig.TomcatWebServerConfig
tobyspring.config.autoconfig.DispatcherServletConfig
스트링 값을 넣어주면 됩니다!
나중에 자동 구성정보를 추가해야한다면 포맷에 맞게 넣어주면 됩니다!
스프링도 잘 동작하는것을 확인 할 수 있습니다.
추상화가 점점 심해지고있는데, 클래스끼리의 관계가 점점 느슨해 지고있습니다.
유지보수에 유리한 코드를 작성하는것은 많은 공부가 필요하지만, 애플리케이션의 확장성과 유지보수면에서 필수적이라는것을 깨달았습니다!