클래스/메서드 메타정보를 이용하여 실제 인스턴스를 호출하는 방법
public class ReflectionTest {
public String methodA() {
return "methodA";
}
}
Class reflectionClass = Class.forName("com.demo.test.ReflectionTest");
ReflectionClass target = new ReflectionClass();
Method methodA = reflectionClass.getMethod("methodA");
Object result = methodA.invoke(target);
리플렉션을 사용하면 클래스와 메서드의 메타정보를 사용해서 어플리케이션에서 동적으로 사용할 수 있지만 런타임에 동작하기 때문에 컴파일 시점에서 오류를 찾기 힘들다.
JDK 동적 프록시는 인터페이스를 기반으로 프록시를 동적으로 생성한다.
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) thrw Trhwable;
}
public interface AInterface {
String call();
}
public class AClass implements AInterface {
@Override
public String call() {
return "call";
}
}
public class CustomInvocationHandler implements InvocationHandler {
private final Object target;
public CustomInvocationHandler(Object object) {
this.target = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) thrw Trhwable {
Object result = method.invokde(target, args);
return result;
}
}
@Slf4j
class JDKDynamicProxyTest {
@Test
void test() {
AInterface target = new AClass();
CustomInvocationHandler handler = new CustomInvocationHandler(target);
AInterface proxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]{AInterface.class}, handler);
String result = (String) proxy.call(); // "call"
log.info("targetClass={}", target.getClass()); // class com.demo.test.AClass
log.info("proxyClass={}", proxy.getClass()); // proxyClass=class com.sun.proxy.$Proxy1
}
}
바이트 코드를 조작해서 동적으로 클래스를 생성하는 기술을 제공하는 라이브러리, 인터페이스가 없어도 구체 클래스만 가지고 동적 프록시 생성 가능
package org.springframework.cglib.proxy;
public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method method, Object[] args, MethodProxy
proxy) throws Throwable;
}
public class AClass {
public String call() {
return "call";
}
}
public class CustomMethodInterceptor implements MethodInterceptor {
private final Object target;
public CustomMethodInterceptor(Object object) {
this.target = object;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) thrw Trhwable {
Object result = method.invokde(target, args);
return result;
}
}
@Slf4j
class CGLIBTest {
@Test
void test() {
AClasss target = new AClass();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(AClass.class); // 구체 클래스 상속
enhancer.setCallback(new CustomMethodInterceptor(target));
AClass proxy = (AClass) enhancer.create();
log.info("targetClass={}", target.getClass()); // com.demo.test2.AClass
log.info("proxyClass={}", proxy.getClass()); // com.demo.test2.AClass$$EnhancerByCGLIB$$25d6b0e3
proxy.call();
}
}