Java

[Java]reflection 을 이용한 간단한 DI 프레임워크 만들기

jay Joon 2020. 8. 17. 01:59

Test 코드는 다음과 같다.

 @Test
    public void DI확인테스트() {
        BookService bookService = SimpleDI.getObject(BookService.class);
        assertThat(bookService).isNotNull();
        BookRepository bookRepository = bookService.getBookRepository();
        assertThat(bookRepository).isNotNull();
    }
    @Test
    public void DI확인테스트2() {
        BookRepository bookService = SimpleDI.getObject(BookRepository.class);
        assertThat(bookService).isNotNull();
    }

TEST1) BookService 를 생성하지않고 내가만 DI프레임워크를 통하여 인스턴스를 생성하고

해당 클래스에 의존받고 있는 BookRepository가 생성되는지  null체크를 해본다.

결과 기대값: ture

 

TEST2) BookRepository를 생성하지않고 내가만 DI프레임워크를 통하여 인스턴스를 생성 후 null 체크

결과 기대값: ture

 

BookRepository

public class BookRepository {}

BookService

public class BookService {

    @Inject
    private  BookRepository bookRepository;

    public BookRepository getBookRepository() {
        return bookRepository;
    }
}

 

 

간단한 DI 프레임워크 소스

 

@Inject Annotation

@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}

Retention 런타임으로 주는 이유는 컴파일 이후에도 JVM 에 의해서 참조를 해야되기 때문에 설정 해야 한다.

(Retention의 default 값은 RetentionPolicy.CLASS 이다.)

 

SimpleDI

public class SimpleDI {
    public static <T>T getObject(Class<T> tClass){
    	//createInstance 메서드를 통해 T 타입의 인스턴스를 받는다
        T instance = createInstance(tClass);
        //stream 을이용하여 instance의 모든 필드를 가져온다.(접근제한자 무시 getDeclaredFields())
        Arrays.stream(instance.getClass().getDeclaredFields())
                .forEach(field -> {
                	 //field에 Anootation중 Inject 만 붙어있는 필드만 type을 받아와서 새로운 인스턴스 생성
                    if(field.getAnnotation(Inject.class)!=null){
                        Object instance1 = createInstance(field.getType());
                        // 접근제한자로 접근하지못하는 필드를 접근하기위한 Field Method.
                        field.setAccessible(true);
                        try {
                            field.set(instance,instance1);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                } );
        return instance;
    }
    
	//주입받은 클래스의 생성자를 통해 인스턴스를생성
    private static <T> T createInstance(Class<T> tClass) {
        try {
            return tClass.getConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

 

리플렉션을이용하여 간단한 DI 프레임워크를 만들어 보았다.