반응형
프록시 생성 방식
프록시(Proxy) : 실제 Target의 기능을 수행하면서 기능을 확장시키거나 추가하는 실제 객체
1. JDK Dynamic Proxy 방식
- 리플렉션을 이용해서 프록시 클래스를 동적으로 생성해주는 방식
- 타켓의 "인터페이스"를 기준으로 프록시 생성
- 사용자의 요청이 타겟을 바라보고 실행될 수 있도록 타겟 자체에 대한 코드 수정이 아닌 리플렉션을 이용한 방식으로
타겟의 위임 코드를 InvocationHandler를 이용하여 작성함
- 사용자가 타겟에 대한 정보를 잘못 주입하는 경우가 발생할 수 있기 때문에 내부적으로 주입된 타겟에 대한 검증 코드 를 거친 후 invoke가 동작(느림)
2. CGLib 방식
- 리플렉션 사용x
- 동적으로 Proxy를 생성하지만, 바이트코드를 조작하여 프록시를 생성해주는 방식
- 인터페이스 뿐 아니라 타겟의 클래스가 인터페이스를 구현하지 않아도 프록시를 생성 함.
- 처음 메소드가 호출된 당시 동적으로 타겟 클래스의 바이트 코드를 조작하게 되고, 그 이후 호출 시부터는 변경 된 코 드를 재사용하여 빠름.
- 리플렉션에 의한 것이 아닌 바이트 코드를 조작하는 방식이기 때문에 성능 면에서 우수함.
CGLib 방식으로 Proxy 구현하기
스프링에서 기본적으로 사용하는 프록시 방식은 CGLib 방식
인터페이스 없이 GreedyStudent 클래스만 작성
package com.greedy.section03.subsection02.cglib;
public class GreedyStudent{
public void study(int hours) {
System.out.println(hours + "시간 동안 열공~~ ");
}
}
호출에 따른 프록시에서 처리할 메소드를 구현하기 위해 InvocationHandler를 구현한 클래스를 작성
package com.greedy.section03.subsection02.cglib;
import java.lang.reflect.Method;
public class Handler implements InvocationHandler{
메소드 호출을 위해 타켓 인스턴스가 필요함.
private final GreedyStudent student;
public Handler(GreedyStudent student) {
this.student = student;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("========== 공부가 너무 하고 싶습니다. ==========");
System.out.println("호출 대상 메소드 : " + method);
for(Object arg : args) {
System.out.println("전달 된 인자 : " + arg);
}
타겟 메소드를 호출하여 타겟 object와 인자를 매개변수로 전달
method.invoke(student, args);
System.out.println("========= 공부를 마치고 수면 학습을 시작합니다 =========");
return proxy;
}
}
코드 구현
package com.greedy.section03.subsection02.cglib;
import org.springframework.cglib.proxy.Enhancer;
public class Application {
public static void main(String[] args) {
인터페이스 없이 GreedyStudent 클래스만 작성하여 cGLib를 이용한 프록시 생성 확인
GreedyStudent student = new GreedyStudent();
Handler handler = new Handler(student);
Enhancer 클래스의 create static 메소드는 타겟 클래스의 메타 정보와 핸들러를 전달하면 proxy를 생성해서 반환
GreedyStudent proxy = (GreedyStudent) Enhancer.create(GreedyStudent.class, handler);
핸들러 코드 구현
proxy.study(20);
}
}
출력 결과
========= 공부가 너무 하고 싶습니다. ============
호출 대상 메소드 : public void com.greedy.section03.subsection02.cglib.GreedyStudent.study(int)
전달 된 인자 : 20
20시간 동안 열공~~
========== 공부를 마치고 수면 학습을 시작합니다 =============
aspectj 의 autoProxy 사용에 관한 설정 시 true 면CGLib 방식으로 false면 JDKDynamic방식으로 동작한다.
ex) @EnableAspectJAutoProxy(proxyTargetClass=true)
반응형
'프로그래밍 > Spring & Spring boot' 카테고리의 다른 글
[Spring / 스프링] Spring MVC구성 요소와 처리 과정 (0) | 2022.09.05 |
---|---|
[Spring / 스프링] Spring Framework 의 특징과 구성모듈 (0) | 2022.09.05 |
[Spring/스프링] 리플렉션 Reflection (0) | 2022.09.05 |
15 Spring : @Aspect , @Before , @AfterAdvice, @AfterReturning, @AfterThrowing, @Around 사용하기 (0) | 2022.09.02 |
14 Spring : @Pointcut 어노테이션 표현식 (0) | 2022.09.02 |