Spring boot AutoConfiguration 동작방식2 - DeferredImportSelector
저번포스팅에서 SpringBoot의 AutoConfiguration 동작에 대해서 기록한 적이 있습니다.
이번에는 이 동작을 이용해서 직접 해당 코드를 작성해보려합니다.
우선 ComponentScan을 제외한 빈 등록 방식을 사용하기 위해서는 다음과 같은 조건을 충족 클레스가 필요합니다.
- import를 통해 불러와지며 ( @Component를 가지고 있지 않아도 됌) DeferredImportSelector , DeferredImportSelector.Group을 구현하고 있는 클래스
그럼 코드를 구현해보겠습니다.
우선 안되는 경우를 위한 테스트를 위해 다음과같이 파일을 구성했습니다.
@Component
public class TestRunner implements ApplicationRunner {
@Autowired
public AnotherComponent anotherComponent;
@Override
public void run(ApplicationArguments args) throws Exception {
anotherComponent.printTest();
}
}
@SpringBootApplication
public class WebTestApplication {
public static void main(String[] args) {
SpringApplication.run(WebTestApplication.class, args);
}
}
@Component
public class AnotherComponent {
public void printTest(){
System.out.println("hello");
}
}
이 경우, 우선 Main으로 실행되는 클래스 경로 외의 다른 패키지의 bean을 등록하려하기때문에 다음과 같은 에러가 발생합니다.
Field anotherComponent in com.example.webtest.TestRunner required a bean of type 'com.example.another.AnotherComponent' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
자 이제 AnotherComponent를 빈으로 등록하도록 webtest패키지 아래 Configuration하나를 추가로 생성해 보겠습니다.
@Configuration
@Import(TestConfiguration.MyImportSelector.class)
public class TestConfiguration {
public static class MyImportSelector implements DeferredImportSelector,DeferredImportSelector.Group{
private AnnotationMetadata meta;
@Override
public String[] selectImports (AnnotationMetadata importingClassMetadata) {
return new String[]{MyImportSelector.class.getName()};
}
@Override
public Class<? extends Group> getImportGroup() {
return MyImportSelector.class;
}
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
meta = metadata;
}
@Override
public Iterable<Entry> selectImports() {
List<Entry> list = new ArrayList<>();
list.add(new Entry(meta, AnotherComponent.class.getName()));
return list;
}
}
}
우선 Import를 통해서 클레스를 등록해야합니다. Import를 통해 불러와진 클레스중, DeferredImportSelector를 구현한 클레스에서 getImportGroup을 호출을 통해 DeferredImportSelector.Group 메서드를 호출할 클레스 정보를 가져오게 됩니다.
이후, process 호출 후, selectImports 과정에서 bean으로 등록할 클레스의 이름을 가져오게 되고, 이속에서 Condition관련 어노테이션 설정 확인 후, bean등록을 하게됩니다.
결과적으로 TestRunner에서는 정상적으로 print가 호출된것을 볼 수 있습니다.