interface가 있음 -> Dynamic Proxy
interface가 없음 -> CGLib
프록시 패턴이란 소프트웨어 디자인 패턴 중 하나로 오리지널 객체(Real Object) 대신 프록시 객체 (Proxy Object)를 사용해 로직의 흐름을 제어하는 디자인 패턴이다
reflection 자체가 애초에 객체의 메모리주소값을 통해서 가져오는것이 아닌, static 영역에 저장된 메타데이터, 클래스 들의 정보를 가져올때 직접 가져오기 때문에 오버헤드 가능성이 높다
Dynamic Proxy가 생성되고, 사용될떄 Reflection API를 활용해서 실제 사용되는 메서드등의 정보를 JVM에 로드된 메타데이터 등에서 가져온다
package proxy;
public interface Animal {
void eat();
void drink();
}
package proxy;
public class Rabbit implements Animal {
@Override
public void eat() {
System.out.println("토끼가 먹습니다");
}
@Override
public void drink() {
System.out.println("토끼가 마십니다");
}
}
package proxy;
public class Tiger implements Animal {
@Override
public void eat() {
System.out.println("호랑이가 먹습니다");
}
@Override
public void drink() {
System.out.println("호랑이가 마십니다");
}
}
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AnimalProxyHandler implements InvocationHandler {
Object target;
public AnimalProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("::: BEFORE :::");
if (method.getName().equals("eat")) {
System.out.println("::: EAT 메서드 호출전 :::");
result = method.invoke(target,args); // 메서드 호출
System.out.println("::: EAT 메서드 호출후 :::");
}
if (method.getName().equals("drink")) {
System.out.println("::: DRINK 메서드 호출전 :::");
result = method.invoke(target,args); // 메서드 호출
System.out.println("::: DRINK 메서드 호출후 :::");
}
System.out.println("::: AFTER :::");
return result;
}
}
package proxy;
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
test1();
}
static void test1(){
Animal rabbit = (Animal) Proxy.newProxyInstance(
Animal.class.getClassLoader(),
new Class[]{Animal.class},
new AnimalProxyHandler(new Rabbit())
);
rabbit.eat();
}
}
- 인터페이스를 만들고, 인터페이스를 오버라이딩 하여 구현한 클래스 준비
- InvcationHandler를 오버라이딩하여, 자신이 처리하고싶은 내용들을 작성한다
- 실제 코드에서 새로운 프록시 객체를 생성할때 인터페이스로 구현한 클래스의 내용들을 잘 넣는다
- 해당 프록시 객체를 실제로 사용할시 우리가 invcationHandler에서 오버라이딩하여 처리한 내용들이 표출된다
public class Rabbit {
public void eat(){
System.out.println("토끼가 먹습니다");
}
}
package org.terror.codeplaygroundspring.proxy;
import net.sf.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
public class AnimalProxyHandler implements InvocationHandler {
Object target;
public AnimalProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Object result = null;
System.out.println("::: BEFORE :::");
if (method.getName().equals("eat")) {
System.out.println("::: EAT 메서드 호출 :::");
result = method.invoke(target, objects);
System.out.println("::: EAT 메서드 호출 끝 :::");
}
return result;
}
}
:::BEFORE:::
::: EAT 메서드 호출:::
토끼가 먹습니다
::: EAT 메서드 호출 끝 :::
package org.terror.codeplaygroundspring.proxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class PrintLogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
System.out.println("::: BEFORE :::");
result = methodProxy.invokeSuper(o, objects);
System.out.println("::: AFTER :::");
return result;
}
}
package org.terror.codeplaygroundspring;
import net.sf.cglib.proxy.Enhancer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.terror.codeplaygroundspring.proxy.PrintLogInterceptor;
import org.terror.codeplaygroundspring.proxy.Rabbit;
public class MethodInterceptorTest {
@Test
@DisplayName("메서드 인터셉터를 활용한 CGLib Proxy 테스트")
public void test1(){
//Enhancer 객체를 생성
Enhancer rabbitEnhancer = new Enhancer();
// setSuperclass() 메소드에 프록시할 클래스 지정
rabbitEnhancer.setSuperclass(Rabbit.class);
// 로그 출력해주는 인터셉터 지정
rabbitEnhancer.setCallback(new PrintLogInterceptor());
Rabbit rabbit = (Rabbit) rabbitEnhancer.create(); // 프록시 생성
rabbit.eat();
}
}
https://velog.io/@suhongkim98/JDK-Dynamic-Proxy%EC%99%80-CGLib