본문 바로가기

Java/Java

(JAVA) 리플렉션 API(4) - 나만의 DI 프레임워크 만들어보기

더보기

요구사항

@Inject 라는 애노테이션 만들어서 필드 주입 해주는 컨테이너 서비스 만들기

public class BookService {


    @Inject

    BookRepository bookRepository;


}

 

ContainerService.java

public static <T> T getObject(T classType)

  • classType에 해당하는 타입의 객체를 만들어 준다.

  • 단, 해당 객체의 필드 중에 @Inject가 있다면 해당 필드도 같이 만들어 제공한다.


코드작성

Inject 애노테이션

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

 

주입클래스

    public static <T> T getObject(Class<T> classType)  {
        
        return null;
    }

 

테스트 클래스 작성

 

BookRepository 클래스

public class BookRepository {

}

BookRepository를 주입받는 BookService 클래스

public class BookService {

    @Inject
    BookRepository bookRepository;
}

테스트 클래스

public class ContainerServiceTest {

}

 

리플렉션을 사용해서 필드에 @Inject  애노테이션이 붙어있을 경우 해당 필드에 대한 인스턴스를 생성해주도록 설계

    public static <T> T getObject(Class<T> classType) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        
        T instance = createInstance(classType);
        Arrays.stream(classType.getDeclaredFields()).forEach(field -> {
            Inject annotation = field.getAnnotation(Inject.class);
            if(annotation != null) {
                Object fieldInstance = createInstance(field.getType());
                field.setAccessible(true);
                try {
                    field.set(instance, fieldInstance);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException();
                }
            }
        });

        return instance;
    }

여기에서 field.set(instance, fieldInstance); 부분은 

해당 파라미터에 필드의 타입인 BookRepository의 인스턴스를 넣어줌으로서 의존성 주입이 완료된다.

 

 

테스트코드

public class ContainerServiceTest {

    @Test
    public void  getObject_BookService() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        BookService bookService = ContainerService.getObject(BookService.class);
        assertNotNull(bookService);
        assertNotNull(bookService.bookRepository);
    }

}

BookService에 대한 인스턴스를 생성하였을때 BookRepository에 대한 인스턴스도 생성되는지 테스트 (by @Inject)

 

 

리플렉션 정리

 

리플렉션 사용시 주의할 것

  • 지나친 사용은 성능 이슈를 야기할 수 있다. 반드시 필요한 경우에만 사용할 것

  • 컴파일 타임에 확인되지 않고 런타임 시에만 발생하는 문제를 만들 가능성이 있다.

  • 접근 지시자를 무시할 수 있다.

 

스프링

  • 의존성 주입

  • MVC 뷰에서 넘어온 데이터를 객체에 바인딩 할 때

하이버네이트

  • @Entity 클래스에 Setter가 없다면 리플렉션을 사용한다.

JUnit


References

 

https://kmongcom.wordpress.com/2014/03/15/%EC%9E%90%EB%B0%94-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98%EC%97%90-%EB%8C%80%ED%95%9C-%EC%98%A4%ED%95%B4%EC%99%80-%EC%A7%84%EC%8B%A4/

 

자바 리플렉션에 대한 오해와 진실

이 글은 크몽 재능인, socurites님이 원고를 기고하셨습니다. 내가 그의 이름을 불러 주기 전에는 그는 다만 하나의 몸짓에 지나지 않았다. 내가 그의 이름을 불러 주었을 때, 그는 나에게로 와서 꽃이 되었다. – 김춘수, “꽃” 주변을 자세히 살펴 보자. 이름만 알고 있다면, 그 물체의 모든 정보를 알 수 있는 것…

kmongcom.wordpress.com

 

ReflectionUtils (JUnit 5.0.3 API)

Read the value of a potentially inaccessible field. If the field does not exist, an exception occurs while reading it, or the value of the field is null, an empty Optional is returned.

junit.org

 

 

Trail: The Reflection API (The Java™ Tutorials)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See JDK Release Notes for information about new fe

docs.oracle.com