Reflection 정의

reflection이란 구체 클래스를 사용하지 않고 메타 정보를 이용하여 해당 클래스의 메소드나 타입에 접근할 수 있도록 도와주는 Java Api이다.

따라서 클래스나 메서드의 메타정보를 동적으로 획득하고, 코드도 접근 제어자와 상관없이 동적으로 호출할 수 있다.

아래와 같은 곳에서 reflection을 사용하고 있다.

  • Spring annotation
  • Spring Aop의 프록시 기술(JDK 동적 프록시)
  package java.lang.reflect;
  public interface InvocationHandler {
       public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable;
}

사용 예시

아래 예를 통해서 확인해보자.

@Test
void test() {
	HelloReflection target = new HelloReflection();
	
    log.info("start");
    String result1 = target.callA();
    log.info("end = ", result1);
    
    log.info("start");
    String result2 = target.callB();
    log.info("end = ", result2);
}

이렇게 위와 같이 동일한 로직이지만 중간에 호출하는 메서드가 달라 공통화하기가 힘든데, 호출 메서들르 동적으로 처리하기 위해 사용하는 기술이 Reflection이다.

Reflection은 클래스나 메서드의 메타정보를 사용해서 동적으로 호출하는 메서드를 변경할 수 있다.

@Test
void reflection() throws Exception {
 	Class classHelloReflection = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$HelloReflection");
	HelloReflection target = new HelloReflection();
    
    
	Method methodCallA = classHelloReflection.getMethod("callA");
    log.info("start");
    Object result1 = methodCallA.invoke(target);
    log.info("end = ", result1);

    Method methodCallB = classHelloReflection.getMethod("callB");
    log.info("start");
    Object result2 = methodCallB.invoke(target);
    
    log.info("end = ", result2);

}
  • Class.forName("hello.proxy.jdkdynamic.ReflectionTest$HelloReflection") 를 사용하여 클래스 메타 정보를 획득한다.
  • getMethod를 통해 해당 클래스의 메서드 메타 정보를 획득한다.
  • invoke(인스턴스)을 통해 획득한 메서드 메타정보로 실제 인스턴스의 메서드를 호출한다.
  • invke를 호출하면서 인스턴스를 넘겨주면 해당 인스턴스의 methodCallA() 메서드를 찾아서 실행한다.

기존에 target.callA()나 target.callB() 메서드를 직접 호출하는 부분이 Method로 바뀌었기 때문에 아래와 같이 공통 로직으로 만들 수 있게 되었다.

@Test
void reflection() throws Exception {
 	Class.forName("hello.proxy.jdkdynamic.ReflectionTest$HelloReflection");
	HelloReflection target = new HelloReflection();
    
	Method methodCallA = classHello.getMethod("callA");
    dynamicCall(methodCallB, target);
    
    Method methodCallB = classHello.getMethod("callB");
    dynamicCall(methodCallB, target);

}

private void dynamicCall(Method method, Object target) throws Exception {
	log.info("start");
    Object result = method.invoke(target);
    log.info("result =", result);
}
  • 정적인 코드를 Reflection을 사용해서 Method라는 메타정보로 추상화 하여 공통 로직을 만들 수 있었다.

결론

Reflection을 사용하면 클래스와 메서드의 메타정보를 사용해서 Application을 동적으로 유연하게 만들 수 있다.
그러나 Reflection 기술은 런타임에 동작하기 때문에, 컴파일 시점에 오류를 잡기 힘들다.
또한 Refleciton을 사용하면 접근 지시자를 무시할 수 있기에 추상화

최근의 타입 정보를 기반으로 컴파일 시점에 오류를 잡아주는 방식에서 역행하는 방식이기에 일반적으로 사용하기를 지양하도록 한다.

0개의 댓글