스프링/스프링 핵심 원리 - 고급편

35. 리플렉션

sdafdq 2024. 1. 20. 16:46

리플렉션이란 클래스나 메소드의 메타 정보를 얻을 수 있는 것 이다.

 

@Test
void reflection1() throws Exception {
    Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");

    Hello target = new Hello();

    Method methodCallA = classHello.getMethod("callA");
    Object result1 = methodCallA.invoke(target);
    log.info("result1={}", result1);

    Method methodCallB = classHello.getMethod("callB");
    Object result2 = methodCallB.invoke(target);
    log.info("result2={}", result2);
}

저렇게.

Class.forName해서 클래스를 찾아온다.

$Hello는 ReflectionTest 클래스 안에 있는 내부 클래스라서 $가 붙은거다.

 

그리고 Method.

저렇게 이름으로 찾아온 클래스 안에 있는 메소드를 또 메소드 이름으로 메타정보를 가져올 수 있다.

invoke는 그 가져온 메타정보의 메소드를 실행하는 거다.

target 안에는 실제 인스턴스가 있어야 한다.

 

target 안에 있는 메소드 메타정보를 찾아 실행 하는 것 이다. 그래서 실제 인스턴스가 필요하다.

 

이렇게 메타 정보를 읽을 수 있으면,

 

private void dynamicCall(Method method, Object target) throws Exception {
    log.info("start");
    Object result = method.invoke(target);
    log.info("result={}", result);
}

이런 식으로 동적으로 메타정보를 인자로 받아서 주는 인자에 따라 실행이 가능하다.

물론 target안에 메소드가 있어야 한다.

 

@Test
void reflection2() throws Exception {
    Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");

    Hello target = new Hello();

    Method methodCallA = classHello.getMethod("callA");
    dynamicCall(methodCallA, target);

    Method methodCallB = classHello.getMethod("callB");
    dynamicCall(methodCallB, target);
}

이런 식으로 쓴다.

 

클래스 정보로부터 메소드의 이름으로 메소드 메타 정보를 뽑고,

 

실제 그 클래스의 인스턴스를 만들고,

그 실제 인스턴스로 부터 메소드 메타정보로 메소드를 찾아 실행한다.

 

 

사실 리플렉션 안쓴다. 왠만해서는. (지금처럼 동적 프록시가 필요할 때 말고는)

런타임에 동적으로 클래스나 메소드의 메타 정보를 얻어오는 것 이다.

 

지금은 콜백도 있어서, 굳이 이럴 필요는 없는데,

 

JDK 동적 프록시 이해하려고 한거다.