동적인 자동 구성 정보 등록

Sol's·2023년 5월 29일
0

토비의 스프링 부트

목록 보기
19/31

지금은 @EnableMyAutoConfiguration 에 자동 구성정보가 하드코딩 되어있습니다.
이것을 동적으로 할당 할 수 있게 변경하겠습니다.
하드코딩은 강한 결합이기때문에 유지보수에 좋지 못하기 때문입니다.

ImportSelector

selectImports() 메소드를 통해 메소드의 이름을 String으로 만들고 그 이름을 구성정보로 스프링 컨테이너가 Bean으로 등록합니다.
우리는 ImportSelector를 한번 더 확장한 DeferredImportSelector를 사용할 것입니다.

DeferredImportSelector는 다른 @Confing붙은 클래스의 Bean설정이 끝난 후에 ImportSelector가 전달받은 구성정보들을 Bean으로 등록합니다.

사실 중요한것은 우리가 DeferredImportSelector를 사용해서 자동 구성 정보동적으로 등록한다는 것입니다

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() 메소드

selectImports 메소드를 통해 외부파일에 String으로 등록된 자동 구성 정보를 읽어와서 import하고있는 어노테이션에 String으로 반환해 줄것입니다.

우선 MyAutoConfiguration 어노테이션을 만들겠습니다.

자동 구성 정보와 관련된 어노테이션이다! 라는것을 알려주기 위함입니다.
어노테이션을 보고 ~겠구나 라고 짐작하는것은 작지만 서비스가 커질수록 중요한것 같습니다.
다음 글에서는 자동 구성 정보 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);
    }
}

어디서 String 정보들을 읽어올까?

ImportCandidates.load를 통해서 String 정보를 읽어옵니다.

아래를 보면 files named META-INF/spring/full-qualified-annotation-name.에서 정보를 읽는것을 알 수 있습니다.

폴더를 만들고

tobyspring.config.autoconfig.TomcatWebServerConfig
tobyspring.config.autoconfig.DispatcherServletConfig

스트링 값을 넣어주면 됩니다!
나중에 자동 구성정보를 추가해야한다면 포맷에 맞게 넣어주면 됩니다!


스프링도 잘 동작하는것을 확인 할 수 있습니다.

느낀점

추상화가 점점 심해지고있는데, 클래스끼리의 관계가 점점 느슨해 지고있습니다.

유지보수에 유리한 코드를 작성하는것은 많은 공부가 필요하지만, 애플리케이션의 확장성과 유지보수면에서 필수적이라는것을 깨달았습니다!

profile
배우고, 생각하고, 행동해라

0개의 댓글