Spring AOP isproxy-based. It is vitally
important that you grasp the semantics of what that last
statement actually means before you write your own aspects
or use any of the Spring AOP-based aspects supplied with the
Spring Framework. - Spring Reference
Spring AOP is
proxy-based.
9.
Proxy is asurrogate object or placeholder for another object to
control access to it. - Gang of Four (gof) design patterns
프록시
사용자가 원하는 실제 객체
사용자
<<interface>>
Proxy
invoke()
Target
invoke()
invoke()
참고) 메소드 명이invoke인 이유는 프록시 패턴의 관례
Target은 클라이언트가 실제로 접근하려는 객체
1. 타깃과 동일한 인터페이스로 구현
public interface Interfaces{
public void invoke()
}
public class Proxy implements Interfaces{
@Override
public void invoke() {}
}
public class Target implements Interfaces{
@Override
public void invoke() { ...isLogic }
}
13.
<<interface>>
Proxy
invoke()
Target
invoke()
invoke()
참고) 메소드 명이invoke인 이유는 프록시 패턴의 관례
Target은 클라이언트가 실제로 접근하려는 객체
1. 타깃과 동일한 인터페이스로 구현
2. 모든 메소드에는 타깃의 위임 코드 작성
public class Proxy implements Interfaces{
@Override
public void invoke() {
if(DB 상태가 나쁘면...){
//delay....
}
Interfaces next = new Target();
next.invoke(); // 타깃 기능 수행
}
}
참고) 메소드 명이invoke인 이유는 프록시 패턴의 관례,
Target은 클라이언트가 실제로 접근하려는 객체
누구를 호출하는거지? Target? Proxy?
→ 신경쓰지마
Proxy에서 타깃의 기능을 호출
→ 호출 시점을 제어가 가능
Proxy
TargetCall
Interfaces.invoke()
기능에 관여 사용자가 원하는 실제 기능 수행
17.
• 별도의 Proxy클래스 구성
• 모든 메소드에서 위임코드 구현
참고) 메소드 명이 invoke인 이유는 프록시 패턴의 관례,
Target은 클라이언트가 실제로 접근하려는 객체
Proxy Target
invoke1()
invoke2()
invoke100()
invoke1()
invoke2()
invoke100()
타깃
Proxy
TargetCall Advice
Intercepts callson an interface on its way to the target. These
are nested "on top" of the target. ... A method invocation
is a joinpoint and can be intercepted by a method interceptor.
@author Rod Johnson by MethodIntercptor.class
MethodInterceptor
40.
public class Handlerimplements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation){
isLogic...
return invocation.proceed();
}
}
method.invoke(new Target(), args)
타깃의 객체 정보가 없음
ProxyFactoryBean factory =new ProxyFactoryBean();
factory.setTarget( [Target] );
factory.addAdvice( [Advice] );
Object proxyBean= factory.getObject();
여러 타깃에 대한 위임코드 관리가 어렵다.
하나 이상의 Handler를 관리할 수 없다.
Advice란 순수한 제어코드
43.
List<Advisor> advisors =new ArraList<>();
addAdvice( advice2 )
Advice advice1
Advice advice2
Advice란 순수한 제어코드
여러 타깃에 대한 위임코드 관리가 어렵다.
하나 이상의 Handler를 관리할 수 없다.
1. 하나 이상의Handler를 관리할 수 없다. → ArrayList<Advisor>
2. 여러 타깃에 대한 위임코드 관리가 어렵다. → 외부로부터 타깃 주입
Handler
InvocationHandler
ProxyFactory
Handler
Advice
ProxyFactory
JDK Proxy
JDK Dynamic Proxy
타깃
Spring
JDK Dynamic Proxy
BeanPostProcessor instances
and AOPauto-proxying Classes that implement the BeanPostProcessor interface
are special and are treated differently by the container.
Spring Reference
57.
Bean BPP
Bean 조작
조작된Bean
BeanPostProcessor
AutoProxing이란
자동으로 타깃 객체를 판별하여 ProxyBean으로 생
성
58.
A more generaland extremely powerful auto proxy creator
is DefaultAdvisorAutoProxyCreator. This will
automagically apply eligible advisors in the current context,
without the need to include specific bean names in the auto-proxy
advisor’s bean definition.
Spring Reference
DefaultAdvisorAutoProxyCreator
@Configurable
public class MyBeanConfig{
@Bean
public DefaultAdvisorAutoProxyCreator bpp() {
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
public Advisor advisor() {
return new DefaultPointcutAdvisor(pointcut, advice);
}
}
Code Generator Library
•인터페이스를 구현하지 않은 클래스에 대해 Proxy를 생성
• 타깃 클래스 자체를 상속하여 Proxy 생성
• Final 클래스나 메소드는 생성 불가
Target
Proxy
extends Target
Target
extends
Handler
super.invoke()
method name : doAction
method name : doNewAction
method name : CGLIB$doAction$0
method name : CGLIB$doNewAction$1
Spring은 CGLIB는 왜권장하지 않았을까?
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. – Spring Reference
71.
net.sf.cglib.proxy.Enhancer 의존성 주입
디폴트생성자
생성자 두 번 호출
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. – Spring Reference
Spring은 CGLIB는 왜 권장하지 않았을까?
(토비의스프링(1권) 참조
CGLIB Proxy는 final 클래스에는 적용할 수 없으
며, 상속을 통해 프록시를 만들기 때문에 해당
클래스의 생성자가 2번 호출된다. 또한 Class단
위로 적용되기 때문에 불필요한 public 메서드에
까지 트랜잭션이 적용된다. 클래스프록시는 코
드를 함부로 손댈 수 없는 레거시 코드나, 여타
제한 때문에 인터페이스를 만들기 어려울 경우
에만 사용해야한다.)
[1] net.sf.cglib.proxy.Enhancer 의존성주입
[2] 디폴트 생성자
[3] 생성자 두 번 호출
3.0 3.2 4.0 4.3
[1] Spring Core 패키지에 포함
net.sf.cglib.proxy.Enhancer.proxy
→ org.springframework.cglib.proxy
75.
[1] net.sf.cglib.proxy.Enhancer 의존성주입
[2] 디폴트 생성자
[3] 생성자 두 번 호출
3.0 3.2 4.0 4.3
[1] Spring Core 패키지에 포함
net.sf.cglib.proxy.Enhancer.proxy
→ org.springframework.cglib.proxy
objenesis 라이브러리를 사용하여
[2]디폴트 생성자가 필요 없고
[3]생성자가 두번 호출 되던 상황도 해결
76.
[1] net.sf.cglib.proxy.Enhancer 의존성주입
[2] 디폴트 생성자
[3] 생성자 두 번 호출
3.0 3.2 4.0 4.3
[1] Spring Core 패키지에 포함
net.sf.cglib.proxy.Enhancer.proxy
→ org.springframework.cglib.proxy objenesis 라이브러리를 사용하여
[2]디폴트 생성자가 필요 없고
[3]생성자가 두번 호출 되던 상황도 해결
Spring 4.3, Spring Boot 1.4
default CGLIB Proxy
#2 안녕하세요~ 반갑습니다!
이제 Spring AOP에 대해, 발표를 !!시작!! 하도록 하겠습니다!
---
...먼저 간단히 제 소개를 드리자면
#3 먼저 간단히 제 소개를 드리자면
저는 문겸이구요.
개발한지 2년차된!!! 주니어 개발자입니다.
특이사항으론 현재 이직을 준비하고 있구요.
지금 발표가 처음이라 많이 긴장은 되는데
준비한 발표 잘 전달해드리도록 하겠습니다.
----
이번 세미나의 큰 주제는 대용량 처리인데,,,
#4 시작하기 앞서 ,
대용량 처리와 무관하게 SpringAOP에 대해 발표하게 된 이유에 대해서 잠시 설명을 드려야될거 같은데요.
사실 아해 스터디에선 매 분기마다 Spring에 관련된 스터디를 진행하고 있는데요.
작년엔 민수님께서 DI에 대해 진행을 해주셨기 때문에
올해는 제가 SpringAOP를 준비하게 되었습니다. --- [[[[[[[[[저는 SpringAOP를 사용할때....
#5 저는 SpringAOP를 사용할때 @AspectJ 스타일 방식과 애노테이션을 같이 사용하는데요.
SpringAOP를 처음보신분들을 위해 제가 간단한 샘플코드를 보여드리겠습니다.
잠시만요.. - “메써드 실행시간 측정 샘플”
[코드 보여줘] a.AspectJStyleTest
방금 보신것처럼 SpringAOP가 어렵지 않다고 생각할 수도 있는데요. 하지만, 방금보신 @AspectJ 스타일 방식은 --- [[[[[[[[[Spring AOP에..
#6 SpringAOP에서 제공하는 한부분이라고 생각하시면 되겠습니다.
무엇보다 SpringAOP를 잘 이해하고 사용하고 싶다면,
사용법 보다는 SpringAOP가 무엇을 기반으로 동작하는지 아셔야되는데요. ---[[[[하지만 많은 개발자분...와 같다...
#7 하지만, 많은 개발자분들이 SpringAOP를 구현할실 때 AspectJ를 쓴다고 해서,
Spring AOP와 AspectJ가 같다고 인식하시는분들이 계시더라구요.
---[[[하지만 AspectJ는 SpringAOP....지원하는 한 가지 방법
#8 하지만 AspectJ는 SpringAOP에서 지원하는 한 가지 방법이라 생각하셔야 됩니다.
저는 이러한 오해를가진 개발자분들을 위해, 좀 더 SpringAOP에 대해 잘 이해하고, 사용할 수 있도록
발표를 준비했는데요.
우선, SpringAOP를 잘 사용하기 위해선, 어떠한 기반으로 Spring AOP가 동작되는지 야셔야됩니다.
---[Proxy 할꺼야]
#9 SpringAOP는 Proxy를 기반으로 동작하는데요.
따라서 Proxy!!!는, SpringAOP의 동작방식에 대해 알 수 있는 매우 중요한 개념입니다.
아무래도 SpringAOP를 이해하기 위해선, 선행적으로 Proxy에대해서 아셔야 되는데요.
--[Proxy란 Proxy패턴에서 접근제어]
#10 Proxy란, Proxy디자인패턴에서 접근제어의 목적으로 사용되는객체를 의미합니다.
다음 그림을 보자면 사용자가 철조망 때문에, 실제로 사용하고 싶은 객체에 접근하지못하고 있습니다.
철조망을 지나기 위해선 문을 통해서 지나가야되는데,
이 문에 있는 열쇠는 Proxy가 가지고 있기 때문에,
사용자는 Proxy라는 애를 통해서만 실제객체에 접근할 수 있는데요.
이처럼 Proxy는 사용자와 실제객체 사이에서 사용자의 요청을 제어하는 목적으로 사용됩니다.
그림만 보자면 Proxy가 불필요하다고
느껴지실 수도 있겠지만,
실제객체에 접근을 제어하는 기능이 상황에 따라 필요합니다. ---[[[[[예를 들자면 사용자가 DB]
#11 예를 들자면,
사용자가 DB에 있는 데이터를 사용하기 위해 DB에 직접 접근한다고 가정을 해보죠.
DB는 접근비용 자체가 많이 소비되는 작업이기 때문에, 사용자의 요청은, DB에게 부담이 될 수 밖에 없고 갑자기 많은 사용자의 요청이 오면, DB가 접속장애를 일으킬 가능성이 높아집니다.
이를 해결하기 위해선 DB의 상태에 따라, 사용자의 요청을 제어하는 기능을 추가해주셔야 되는데요.
물론, 코드안에 내부적으로 기능을 구현할 수 있지만, 이는 중복코드가 발생될 위험이 있습니다.
-[Proxy 클래스를 구성하면]
#12 이런 경우 사용자와 DB 사이에 Proxy 클래스를 구성하면 되는데요.
일반적으로 Proxy 클래스를 구성을 할땐,
사용될 실제객체와 동일한 인터페이스를
사용하여 개발하는데요...
--- [다음과 같이 Proxy를 구성... 인터페이스]
#13 다음과 같이 Proxy 클래스를 구성하실 땐
실제객체 즉 타깃과 동일한 인터페이스를 사용하여, Proxy 클래스를 구성하시면 됩니다.
여기서 Proxy 클래스의 메써드명이 invoke인 이유는 Proxy패턴의 관례라 할 수 있는데요.
예를들자면 우리가 클래스 이름을 지을때, 첫 글자는 무조건 대문자로 짓는것처럼
Proxy패턴에선 Proxy 클래스의 메써드명을 invoke라고 짓는것이
디자인 패턴에서 존재하고 있는 하나의 약속이라 생각하시면 되겠습니다.
---[Proxy 클래스를 생성되었다.. 위임코드]
#14 이제 Proxy 클래스가 구현이 되었다면
사용자의 요청을 제어하는 기능을 구현하셔야 되는데요.
이때 타깃이 아닌
Proxy의 invoke() 메써드에서 접근제어기능을 구현하시면 됩니다.
다음으론 Prox에 있는 모든 invoke 메써드에는 타깃에 대한 위임 코드를 작성해주셔야 됩니다.
이점은 Proxy패턴에서 나타나는 특징중 하나인데요.
최종적으로 사용자의 요청이 타깃이 아닌 Proxy를 통해 타깃이 호출되기 때문입니다.
따라서 기존과 동일하게 사용자의 요청이 타깃을 그대로 바라볼 수 있도록
Proxy에 있는 모든 invoke 메써드에는 타깃에 대한 위임코드를 의무적으로 구현 해주셔야됩니다.---[사용자의 호출 코드]
#15 마지막으로
사용자의 호출코드를 Target이 아닌 Proxy로 바라볼 수 있도록 변경만 해주시면 되는데요.
이제 사용자의 요청에 의해 Proxy가 어떻게 동작되어지는 살펴보겠습니다.
–[사용자는 인터페이스 타입으로 invoke 메써드 호출하게 되면,]
#16 사용자는 인터페이스 타입으로 타깃의 invoke 메써드를 호출하게 되면,
내부적으로 Proxy의 invoke 메써드가 먼저 호출됩니다.
Proxy에선 사용자가 원하는 타깃에 대한 기능이아닌 DB의 상태만 검증을 하고,
사용자가 원하는 기능은 위임코드를 통해 타깃의 메써드를 호출하게 됩니다.
타깃의 메써드는 사용자가 원하는 기능을 수행하여 결과를 사용자에게 제공해 주는데요.
–[따라서 Proxy는 사용자가 요청하는 타깃의 기능엔 전혀 관여하지 않기 때문에]
#17 따라서 Proxy는 사용자가 요청하는 타깃의 기능엔 전혀 관여하지 않기 때문에
사용자는 Proxy존재에 대해 신경쓸 필요가 없게 됩니다.
또한, Proxy의 invoke 메써드안에서
타깃의 호출시점을 제어할 수 있기 때문에,
사용자가 원하는 invoke 메써드가 호출되기 전 또는 후에 타깃에 영향을 주지 않고, 또 다른 기능을 수행할 수 있습니다.
이러한 특징 떄문에 Proxy패턴을 활용하여 다양한 기술에 적용하여 사용하고 있는데요.
하지만 Proxy패턴을 통해 Proxy 클래스를 구현하는 과정에서 아쉬운점이 몇가지 존재합니다. – [우선, Proxy 를 구성하기 위해선 ]
#18 우선, Proxy 클래스를 구현하기 위해선
반드시 타깃과 동일한 인터페이스를 구현하는 과정이 필요합니다.
이 과정에서 Proxy 클래스안에 있는 모든 invoke 메써드는
타깃에 대한 위임코드를 작성해주셔야 되는데요.
아무래도 타깃에 대한 메써드가
늘어날 수록, Proxy에서도 늘어난 메써드마다 위임코드를 작성해줘야 되기때문에 위임코드를 관리하기가 쉽지 않습니다.
위임코드에 대한 문제점을 해결할 수 있도록
자바에선 기본적으로 Proxy를 구현해주는 클래스를 제공해주는데요. –[바로 JDK Dynamic Proxy를 사용하면 되는데요.]
#19 바로 JDK Dynamic Proxy입니다.
JDK Dynamic Proxy란 이전 보았던 Proxy패턴의 구조적인 한계를 리플렉션의 기술을 활용하여 Proxy를 생성해주는 기능이라 할 수 있는데요.
이 기능은 리플렉션 패키지에 있는 Proxy라는
클래스를 통해 구현할 수 있습니다.
이 클래스는 동적으로 Proxy를 생성해준다고 해서 JDK Dynamic Proxy라 불립니다. –[Proxy 객체는 newProxyInstance 메써드를 통해 반환받을 수 있는데요.]
#20 Proxy 객체는 newProxyInstance 메써드를 사용하여 생성할 수 있는데요.
우선 메써드의 구성을 살펴보자면
첫 번째 파라미터는 동적으로 Proxy 생성해주기 위해 클래스로더가 필요합니다.
두 번째는 인터페이스가 필요한데요.
Proxy는 기본적으로 Target과 동일한 인터페이스를 구현하기 때문에
이 파라미터엔 타깃의 인터페이스를 제공해주면 됩니다.
마지막으론 InvocationHandler라는 인터페이스를 구현해서 넘겨주셔야 되는데요.
눈치 채신 분들도 있겠지만, invocationHandler는 Proxy클래스의 invoke 메써드를 관리해주는 인터페이스라고 할 수 있습니다.
다음 세 가지 파라미터 중 Proxy 패턴의 위임코드에 관련된 문제점을 개선해준 애가 바로 InvocationHandler 인데요. ---[우선 InvocationHandler를 살펴보자면,]
#21 우선 InvocationHandler를 살펴보자면,
지금까지 강조했던 invoke라는 하나의 메써드만 존재하는 인터페이스입니다.
따라서 invoke 메써드 안에서 타깃에 대한 접근제어기능을 구현하시면 됩니다.
– [메써드 타입의 파라미터를 활용하여]
#22 위임코드는 메써드 타입의 파라미터를 활용하여
타깃에 대한 메써드호출을 할 수 있습니다.
샘플 코드를 보여드리자면...
[코드 보여줘] b. isJDKDynamicProxyCreator
보신거와 같이 Proxy 클래스를 별도로 구성하지 않아도
invocationHandler를 구현하여 Proxy 객체를 간단히 생성할 수 있었는데요.
이러한 이유엔 JDK Dynamic Proxy가 어떻게 생성되는지 아셔야됩니다.
---
JDK Dynamic Proxy는 크게 3가지 절차를 통해 내부적으로 Proxy를 생성해주고 있는데요.
#23 JDK Dynamic Proxy는 크게 3가지 절차를 통해 내부적으로 Proxy를 생성해주고 있는데요.
---
우선, 사용자에 의해 프록시 생성메써드를 호출하게 되면
가장 먼저 타깃의 인터페이스를 복사합니다.
#24 우선, 사용자에 의해 프록시 생성메써드를 호출하게 되면
가장 먼저 타깃의 인터페이스를 복사합니다.
복사된 인터페이스와 외부로부터 전달받은 클래스 로더를
프록시 팩토리에게 전달하고, Proxy객체를 생성해달라고 요청을 합니다.
----
프록시 팩토리에선
타깃의 인터페이스를 구현한 새로운 Proxy 객체를 생성하여 반환해주는데요.
#25 프록시 팩토리에선
타깃의 인터페이스를 구현한 새로운 Proxy 객체를 생성하여 반환해주는데요.
이 점은 JDK Dynamic Proxy의 중요한 특징이라고 보시면 되겠습니다.
-----
마지막으로 생성된 Proxy 객체에 InvocationHandler를
포함시켜 하나의 Proxy객체로 반환해줍니다.
#26 마지막으로
생성된 Proxy 객체에 InvocationHandler를
포함시켜 하나의 Proxy객체로 반환해줍니다.
JDK 다이나믹 프록시는 다음과 같은 하나의 Proxy 객체 안에 handler가 포함된 구조를 띄고 있는데요..
---
Proxy 패턴과 비교해보자면
#27 Proxy 패턴과 비교해보자면
사용자의 요청이 Proxy를 통해서
타깃에게 전달된다는 점은 같지만,
가장 큰 차이점은, 아무래도 InvocationHandler를 포함하고 있다는 점입니다.
----
기존의 Proxy패턴은
Proxy에서 타깃의 메써드를 호출하기 위해,
#28 기존의 Proxy패턴은
Proxy에서 타깃의 메써드를 호출하기 위해,
invoke 메써드마다 위임코드를 작성했었는데요,
이 때문에 타깃의 메써드가 추가될 수록 위임코드를 관리하기 어렵다는 구조적인 한계가 존재했습니다.
----
하지만,
JDK Dynamic Proxy는 Proxy를 생성할 때 타깃의 인터페이스의 주입을 받는데요.
#29 하지만,
JDK Dynamic Proxy는 Proxy를 생성할 때 타깃의 인터페이스의 주입을 받는데요.
이때 자체적으로 인터페이스에 존재하는 모든메써드의 정보를
handler에게 제공해줍니다,
따라서 handler의 invoke 메써드에선
사용자의 요청을 처리할 타깃의 정보만 제공해주면
타깃에 존재하고 있는 모든 메써드 호출을 관리할 수 있다는 장점이 생깁니다.-[JDK Dynamic Proxy에서도 아쉬운점이 있다면]
#30 JDK Dynamic Proxy에서도 아쉬운점이 있다면
[바로 하나 이상의 Handler를 등록할 수 없다는 점인데요.]
#31 바로 하나이상의 Handler를 등록할 수 없다는 점인데요.
만약, 타깃에게 여러Proxy를 적용해주기 위해선
handler 안에있는 invoke 메써드에서 해결(을)해야 되기 때문에
중복코드가 발생될 가능성도 높아지고,
무엇보다 코드가 복잡해질 수 밖에 없습니다.
-------[위임코드의문제 – 1핸들러 n타깃 핸들러 안에 직접 제공 받아야함..]
또한, 하나의 핸들러로 여러 타깃에 대해 Proxy를 적용을 할 때도 동일한 문제가 생기는데요.
#32 또한,
하나의 핸들러로 여러 타깃에대해
Proxy를 적용을 할 때도 동일한 문제가 생기는데요.
예를들어 여러 타깃 객체에 존재하고 있는
, 모든 메써드호출에 대해
하나의 Handler를 사용하여 제어한다면 이전과 동일하게
invoke 메써드에서 해결을해야되기 때문에
결과적으로 Handler를
재사용하기 어렵다는 문제가 발생합니다.
무엇보다 이러한 이슈가 발생한 이유는
JDK Dynamic Proxy가 타깃의 인터페이스를 기준으로 Proxy 객체만 생성해주기 때문에
타깃의 정보는 InvocationHandler에서 직접적으로 전달받고 있기 때문입니다.
----
하지만 Spring은 JDK Dynamic Proxy가 가지고 있었던 한계를 개선하고,
기본적으로 JDK Dynamic Proxy를 기반으로 SpringAOP를 제공해주고 있는데요.
#33 하지만 Spring은 JDK Dynamic Proxy가 가지고 있었던 한계를 개선하고,
기본적으로 JDK Dynamic Proxy를 기반으로 SpringAOP를 제공해주고 있는데요.
---
그렇다면 Spring에선 어떻게 JDK Dynamic Proxy의 한계를 해결했는지에 고민할 필요가 있습니다.
저는 ProxyFactoryBean이라는 Spring에서 제공해주고 있는 클래스를 통해서 확인해보려 합니다.
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-introduction
#34 그렇다면 Spring에선 어떻게 JDK Dynamic Proxy의 한계를 해결했는지에 고민할 필요가 있습니다.
저는 ProxyFactoryBean이라는 Spring에서 제공해주고 있는 클래스를 통해서 확인해보려 합니다.
#35 이 ProxyFactoryBean은 Spring에서
AOP Proxy를 생성할 수 있는 여라가지 방법중에 가장 기본적으로 사용되는 방식입니다.
우선 ProxyFactoryBean에 대해 잠시 설명을 드리자면,
Proxy를 자체적으로 생성해주고, 생성된 Proxy를 Bean으로 등록해주는 클래스인데요.
----
ProxyBean을 생성하기 위해선 기본적으로 다음과 같은 메써드가 필요한데요.
#36 ProxyBean을 생성하기 위해선 기본적으로 다음과 같은 메써드가 필요한데요.
이 중에서 하나 이상의 invoke 핸들러를 관리할 수 없었던 문제를 어떻게 개선되었지 보기 위해선 Advice라는 애를 보시면 됩니다.
----
Advice는 최상위 인터페이스로 구성되어 있고,
그 밑에 Advice를 확장한 세 가지 인터페이스가 따로 존재합니다.
그 중에서도 interceptor라는 인터페이스는 유일하게 타깃에 대한 호출을를 가로챌 수 있는 있는 인터페이스입니다.
#37 Advice는 최상위 인터페이스로 구성되어 있고,
그 밑에 Advice를 확장한 세 가지 인터페이스가 따로 존재합니다.
그 중에서도 interceptor라는 인터페이스는 유일하게 타깃에 대한 호출을를 가로챌 수 있는 있는 인터페이스입니다.
----
이 인터페이스를 확장한 인터페이스 중에
이전에 보았던 invocationHandler와 같이 타깃에 대한 메써드의 호출을 가로챌 수 있는 인터페이스가 바로 메써드인터셉터인데요.
#38 이 인터페이스를 확장한 인터페이스 중에
이전에 보았던 invocationHandler와 같이 타깃에 대한 메써드의 호출을 가로챌 수 있는 인터페이스가 바로 메써드인터셉터인데요.
----
이 인터페이스 구성도 invocationHandler와 마찬가지로 invoke() 메써드만 구성되어 있고
#39 이 인터페이스 구성도 invocationHandler와 마찬가지로 invoke() 메써드만 구성되어 있고
---
실행 절차도 타깃보다 먼저 수행을 하고 있습니다.
하지만 차이점이 하나 존재하는데요.
#40 실행 절차도 타깃보다 먼저 수행을 하고 있습니다.
하지만 차이점이 하나 존재하는데요.
-- 위임코드차이
#41 바로 위임코드의 차이입니다.
보시다싶이 메써드인터셉터는 proceed라는 메써드를 통해 다음 위임 코드가 결정이 되고 있는데요.
---[setTarget 타깃정보 미리 제공]
#42 이 점은 ProxyFactoryBean을 구현할 당시에 setTarget 메써드를 통해서 타깃의 객체정보를 팩토리에게 제공을 해주면
Proxy가 생성될 시점에 자동으로 handler에게 타깃 정보를 제공해주기 때문입니다.
결과적으로 Advice라는 handler는 타깃에게 종속받지 않고 순수하게 제어코드만을 작성할 수 있기 때문에, 기존의 한계였던 여러 타깃에 대한 위임코드 관리가 어렵지 않습니다.
코드를 잠시 보시자면...
[코드 보여줘] c.AddAdviceTest
방금 보신 코드를 통해 위임코드에 대한 문제가 해결되었다는걸 확인할 수 있었는데요. ---[Handler를 관리할 수 없었던 문제를 어떻게 ]
#43 다음으론 하나 이상의 Handler를 관리할 수 없었던 문제를 어떻게 개선했는지 Advice라는 Handler가 등록되어지는 과정을 통해 살펴보도록 하겠습니다. ---[리스트 형식으로 저장되는 advic핸들러]
#44 Advice는 내부적인 프로세스에 의해
!!!Advisor!!!라는 타입으로
ArrayList에 등록을 시켜주게 되는데요.
따라서 여러 Handler를 관리할 수 있는게 되는거죠.
여기서 처음으로 Advisor란 용어가 나오는데. –[advisor 용어설명]
#45 Advisor란 Spring AOP에서만 사용되는 AOP 용어인데요.
Spring에서는 Pointcut 과 Advice를 묶어 Advisor라 부르는데,
이러한 이유엔 여러 핸들러를 관리할 수 없었던 문제를 ArrayList로 해결하였기 때문인데요. ---[[[[[어드바이스 어디에적용
#46 여러 Advice가 등록이 가능해지면서,
Advice를 어디에 적용해야할지 애매지기 때문이죠.
--[이러한 문제를 해결하기 위해... Pointcut, Advice]를 묶어
#47 이러한 문제를 해결하기 위해 Spring은 Advisor라는 타입으로 Advice와 Pointcut을 묶어 등록을 해주고 있습니다.
따라서 Spring에선 포인트컷과 어드바이스를 Advisor라는 용어로 부르고 있습니다.
--- [[[ 이러한 이유 때문에 단순히 addAdvice 메써드를 통해 Advice만 등록했을 때도,
#48 이러한 이유 때문에 단순히 addAdvice 메써드를 통해 Advice만 등록했을 때도,
내부적으로 Pointcut True라는 옵션으로 묶어 리스트에 등록을 해주고 있습니다.
그다음으로 Pointcut.True 옵션을 알아보기 위해 Pointcut에 대해 알아보도록 하겠습니다.
#49 Pointcut은 Advice가 어디에 적용될지 식별할 수 있는 인터페이스인데요.
구성은 다음과 같습니다.
먼저 클래스를 식별하여 Advice를 적용할 때 사용되는 ClassFilter와
그다음으론 메써드를 식별할 수 있는 메써드메처
마지막으로 이전에 보았던 모든 곳에 적용할 수 있는 True 옵션이 존재합니다.
따라서 Pointcut 인터페이스를 구현한 클래스들은
크게 클래스를 식별할지, 또는 메써드를 식별할지에 따라서 ClassFilter 인터페이스
또는 MethodMatcher 인터페이스를 상속받아 구현하고 있습니다.
#50 대표적으로 메써드 이름을 식별할때 사용되는
네임.매치.메써드.포인트컷 클래스에도
Pointcut 인터페이스를 상속받았기 때문에 의무적으로 ClassFilter 옵션은 True로 지정해주고 있습니다.
내부적으로 확인해볼 수 있는지
#51 이제 소개해드린 Pointcut과 Advice를 활용하여 Advisor로 등록해줘야 하는데요.
이러한 고민을 할 필요가 없는게 ProxyFactoryBean 클래스가 내부적으로 DefaultPointcutAdvisor 클래스를 이용하여 Advisor 리스트에 등록을 해주고 있습니다.
이와 마찬가지로 Advior를 구현하실때 이 클래스를 사용하시면 되는데요.
[코드 보여줘]
e.AdvisorProxyFactoryTest
코드를 보셨듯이 빈으로 등록된 Advisor를 활용하는 방법을 보여드렸는데요.
다음으로 타깃의 로직이 어떻게 수행되는지 알아보겠습니다.
#52 동작원리는 다음과 같은데요.
사용자에의해 타깃의 메소드가 호출되는 시점에 ProxyFactory에서 동적으로 ProxyBean을 생성해줍니다.
[1] 그다음 Pointcut이 호출이 되는데요.
[2] Pointcut은 호출된 메써드 정보와 팩토리로부터 제공받은 타깃의 정보를 비교합니다.
[3] 이러한 검증 과정이 통과가되면 Advice가 호출되구요.
[4] 마지막으로 Advice에 있는 위임코드를 통해 타깃의 메써드가 호출됩니다.
여기까지 기본적인 AOP Proxy의 동작과정에 대해 알아보신건데요.
다음으론 이전에 있었던 한계들을, 다시 비교하여 정리해보겠습니다.
#53 기존엔 여러 Handler를 관리할 수 없었던 문제는
ArrayList에 등록하여 해결을 했고, 이 과정에서 Advisor라는 용어에 대해 알아보셨습니다.
두 번째론 여러 타깃에 대한 위임코드의 문제가 있었는데요.
Spring은 타깃 객체의 정보를 Handler가 아닌 외부에서 주입받는 방식으로 해결을 했습니다.
#54 따라서 Advice와 Pointcut은 타깃에 대해 의존하지 않기 때문에
Advisor에 의해 조합하여 사용할 수 있습니다.
하지만 Proxy FactoryBean도 해결해야될 문제가 있는데요.
#55 바로 타깃과의 관계입니다.
Proxy FactoryBean을 통해 Proxy Bean을 생성하기 위해선 반드시 타깃의 정보를 주입받으셔야되는데요.
아무래도 여러 타깃에 대해 Proxy를 적용하기 위해선 Bean설정코드가 많아지게 되고,
무엇보다 동일한 어드바이져를 사용하고 있지만 타깃의 정보만 바뀐 코드들이 많아지게 됩니다.
Spring은 이러한 문제를 다음과 같이 해결하고 있는데요.
#56 바로 AutoProxing입니다.
AutoProxing는 Spring에서 AOP를 구현하실 때 자주 접하게 되는 용어중 하나인데요.
AutoProxing이란 자동으로 타깃 객체를 판별하여 ProxyBean으로 생성해주는 개념입니다.
#57 Spring에선 AutoProxing의 기술을 흔히 !!!BPP!!라고 불리는 Bean Post Processor를 통해 해결했는데요.
#58 BPP란 IoC 컨테이너에 등록된 빈이 생성되는 !!!시점!!!,
전후에 빈을 조작하고,
조작된 빈을 사용할 수 있도록 Spring에서 제공해주는 인터페이스입니다.
빈을 조작하기 위해선 BPP를 구현해서 빈으로 등록해주시면 됩니다.
Spring에서는 autoProxing을 할 수 있도록 다양한 BPP를 제공해주고 있습니다.
#59 그 중에서도 다음과 같은 디폴트 어드바이저 오토 프록시 크리터라는 BPP를 사용하시면 됩니다.
이 BPP의 특징은 Advisor가 빈으로 등록이 되어있으면,
자체적으로 Advisor에 등록된 Pointcut과 Advice를 사용해서 자동으로 ProxyBean를 생성해줍니다.
#60 이 BPP가 빈으로 등록되면
[1] 빈이 호출되는 시점에 BPP에 거치게 되는데요.
[2] 다음으론 호출된 빈의 정보와 Pointcut을 통해 검증 과정이 이뤄지고.
[3] 검증이 끝나면 내부적인 프록시 팩토리에 의해서 ProxyBean이 생성됩니다.
구현방식도 되게 간단한데요.
#61 다음과 같이 등록된 Advisor 빈이 있다면
디폴트 어드바이저 오토프록시크리터 클래스를 빈으로 등록만 해주면 됩니다.
코드를 잠시 보자면...
[코드 보여줘] – f.AutoProxingTest
방금 보신 코드를 통해 타깃에 대한 별도의 빈설정 없이 AutoProxing이 된다는걸 확인할 수 있었구요.
지금까지 보았던 상황들을 다시 정리를 해보자면
#62 기존의 Proxy 패턴은 타깃에 대한 접근 제어의 목적으로
새로운 Proxy 클래스가 구성되면서 사용자의 호출이 그대로 타깃의 메써드를 바라볼 수 있도록
Proxy 클래스의 메써드마다 위임코드를 구현해주었는데요.
이 때문에 중복코드가 발생되었습니다.
이 문제점을 개선하기 위해 InvocationHandler가 등장했고,
타깃에 대한 모든 메써드의 호출은 invoke 메써드에서 제어할 수 있었습니다.
#63 하지만 JDK Dynamic Proxy는 여러 Handler를 관리할 수 없다는 단점이 존재했고
이를 개선하기위해 Spring에선 Advisor가 등장했습니다.
또한, 타깃의 정보는 Handler가 아닌 외부로 부터 제공받기 때문에
Pointcut과 Adivce를 독립적으로 관리할 수 있게 되었습니다.
#64 하지만 Proxy FactoryBean은 하나 이상의 타깃을 등록할 수 없다는 한계 때문에, 중복된 빈설정코드가 나타났습니다.
이를 해결하기 위해 BPP를 사용하여 Bean이 생성된 시점에, Advisor Bean을 통해 ProxyBean으로 조작하여 해결할 수 있었습니다.
Spring의 AOP Proxy 메커니즘은 BeanPostProcessor를 활용하여 구현되었습니다.
전체적인 Spring AOP의 동작방식에 대해 알아보기 위해
JDK Dynamic Proxy를 기준으로 보여드렸는데요.
#65 JDK Dynamic Proxy 이외에도 SpringAOP엔 CGlib이라는 방식이 존재합니다.
Spring AOP가 두 가지 방식을 지원하는 이유는 JDK Dynamic Proxy로 해결할 수 없는 문제가 있기 때문입니다.
#66 바로 다음과 같은 상황인데요.
이 자료는 스택 오버 플로우에 게시된 JDK Dynamic Proxy를 사용하면서 발생된 여러 이슈 하나입니다.
상황을 설명드리자면
외부 라이브러리에 존재하는 인터페이스의 기능을 확장하고 싶어서 구현 객체에 새로운 메써드를 추가하고
인터페이스가 아닌 클래스를,
빈을 주입받는 과정에서
런타임 에러가 발생되었다고 합니다.
이 상황은 JDK Dynamic Proxy가 어떻게 생성되는지 몰랐기 때문인데요.
JDK Dynamic Proxy의 생성과정을 다시한번 더 살펴보자면..
https://stackoverflow.com/questions/37726351/can-not-set-field-to-com-sun-proxy-proxy/37726709
#67 다음과 같이 JDK Dynamic Proxy는 인터페이스를 구현하여,
Proxy 객체를 생성해주는데요.
따라서 JDK Dynamic Proxy를 사용하땐 반드시, 인터페이스 타입으로 주입을 받으셔야 됩니다.
하지만, 인터페이스 타입이 아니더라도 CGlib을 사용하면 간단히 해결할 수 문제인데요.
다음으론 CGlib에 대해 알아보겠습니다.
#68 CGLib은 Code Generator Library의 약자로 바이트코드를 조작하여 Proxy를 생성해주는데요.
CGlib은 3 가지 특징을 가지고 있습니다.
첫 번째론 타깃이 하나 이상의 인터페이스를 구현하고 있지 않다면,
Spring에 의해서 자동으로 CGlib방식으로 Proxy로 생성해줍니다.
이 과정에서 CGlib은 타깃을 상속받아 Proxy를 구성하고 타깃에 대한 모든 메써드를 바이트 코드로 재정의하여 사용합니다.
특히 바이트 코드를 조작하여 Proxy를 생성해주기 때문에, JDK Dynamic Proxy와 성능의 차이가 납니다.
#69 우선 JDK Dynamic Proxy는 기본적으로 인터페이스를 기준으로 Proxy를 생성해주기 때문에
실제 동작할 타깃의 객체는 Invoke 메써드에서 구현해야합니다.
이과정에서
검증되지 않는 객체가 주입될 가능성이 있기 때문에,
Proxy를 호출 할때마다 주입된 객체에 대한 검증과정이 이뤄지는데요.
이 때문에 JDK Dynamic Proxy는 속도가 느릴 수 밖에 없습니다.
#70 하지만 CGLIB은
메써드가 처음 호출되었을때 동적으로 ByteCode를 생성해주고
두 번째 호출부터는
수정된 ByteCode를 재사용하기 때문에
아무래도 JDK Dynamic Proxy보다 속도가 빠를 수 밖에 없습니다.
#71 그렇다면
왜?!
성능이 좋은 CGLIB을 사용하지 않고,
Spring은 JDK Dynamic Proxy를 기반으로 AOP를 생성해주고 있을까요?
#72 사실 CGlib은 몇가지 한계가 있는데요.
Spring에선 기본적으로 지원하지 않았기 떄문에,
별도로 의존성을 추가하여 개발을 했습니다.
[1]그다음으론 CGLIB을 구현하기 위해선, 반드시 default 생성자가 필요했고,
생성된 Proxy를 호출하게 되면 생성자가 2번 호출된다는
한계가 있었는데요.
하지만 Spring boot에선 기본적으로 CGlib을 사용하여 Proxy로 생성해주고 있습니다.
#73 이러한 이유에 대해선 SpringBoot 깃헙에서 찾아볼 수 있었는데요.
어느 개발자가
”인터페이스를 구현한 클래스가 왜 씨지립으로 생성되고 있냐”라고 물어봤는데,
이에 Spring Boot의 리더인 Phil webb은
JDK Dynamic Proxy가 오류를 발생할 가능성이 높다고 말을 했습니다.
아무래도 이러한 상황이 이해가 가질않아
Spring 레퍼런스를 추적하여 CGlib이 어떻게 변화가 되었는지 정리를 해봤는데요.
https://github.com/spring-projects/spring-boot/issues/8434
#74 다음과 같이 3가지의 단점이 존재했는데요.
https://docs-stage.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-api – 4.0
#75 3.2 부터 CGLIB을 Spring Core 패키지에 포함이 되어,
더이상 의존성을 추가하지 않아도 개발을 할 수 있게 되었습니다.
https://docs-stage.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-api – 4.0
#76 그 다음 4 버전 부터는
Objensis(오브젠시스) 라이브러리의 도움을 받아,
default 생성자가 없이도 Proxy를 생성할 수 있게 되었고,
생성자가 두 번 호출되던 상황도 같이 개선이 되었습니다.
https://docs-stage.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-api – 4.0
#77 기존에 있던 CGLIB의 이슈들이 개선이 되면서 현재는 Proxy가 기본적으로 CGLIB으로 생성되도록 변경되었습니다.
지금까지 CGlib에 대해서 모두 알려드렸는데요.
https://docs-stage.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-api – 4.0
#79 어떤 상황이냐면,
같은 클레스에 있는 메써드 호출을 할때
AOP를 적용할 수 없는 문제가 발생합니다.
이 문제는 자가호출 또는 Self-invocation이라 하는데요.
보시다싶이 SpringAOP만의 문제가 아니라,
트랜잭션을 사용할 때도 발생되는 문제이구요.
https://stackoverflow.com/questions/16899604/spring-cache-cacheable-not-working-while-calling-from-another-method-of-the-s
https://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo
https://stackoverflow.com/questions/42921388/same-class-invoke-not-effective-in-spring-aop-cglib
https://stackoverflow.com/questions/52619924/how-to-execute-transaction-in-hibernate-while-throwing-exception
#80 또한, @캐쉬에서도 발생할 수 있는 문제입니다.
하지만 대부분 개발자들이 이 문제에 대해 모르는 경우가 많아요.
무엇보다 Self invocation이 발생하는
근본적인 이유는
Spring에서 사용되는
AOP기술들이
Proxy기반으로 동작하기 때문인데요. Proxy메커니즘에 대해 다시 살펴보자면
https://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo
https://stackoverflow.com/questions/42921388/same-class-invoke-not-effective-in-spring-aop-cglib
https://stackoverflow.com/questions/52619924/how-to-execute-transaction-in-hibernate-while-throwing-exception
#81 [1] 사용자가 Proxy를 통해 타깃의 메써드를 호출하게 되면
Proxy는 타깃의 메써드에 대한 어드바이스를 수행합니다.
[2] 그다음 타깃의 메써드가 수행이되는데요.
여기서 중요한점은 Advice는 Proxy에서만 이뤄지기 때문에,
타깃의 메써드가 호출될 시점엔 AOP가 동작이 되지 않습니다.
하지만 해결방법은 존재하는데요,
#82 첫 번째로 소개할 방법은 로드존슨의 대처 방안 입니다.
로드존슨은 다 아실텐데,
Spring에서 사용되는 대부분의 AOP의 기술들이 로드존슨에 의해 만들어져 있는데요.
#83 로드존슨은 Self Invocation 상황을 대비하여 AopContext란 클래스를 별도로 만들었는데요.
이 클래스에 있는
currentProxy()라는 메써드를 사용하면 문제를 해결할 수 있습니다.
이 메써드는 타깃에서 메써드가 수행이 될때도 Proxy 객체를 반환받기 위해 사용되는데요.
단 AopContext를 사용하기 위해선 몇 가지 조건이 있습니다.
#84 첫 번째 조건은 사용자의 호출이 Proxy를 통해 호출되어야 됩니다.
두 번째는 익스포즈프록시라는 옵션을 활성화를 해주셔야 되는데 이 옵션에 대해서는 많이들 보셨을꺼에요
단순히 AOP를 사용하기 위해 의무적으로 옵션을 추가했던게 아니라
타깃의 영역에서 기능을 수행할때도 언제든 Proxy 객체에 접근할 수 있도록 활성화를 해준겁니다.
이 옵션은 AOP Proxy에 관련된 클래스나 애노테이션에 기본적으로 제공해주고있구요.
예를들어 ProxyFactoryBean에도 setExposeProxy 옵션이 존재하고,
autoProxing을 위해 사용하였던 애노테이션에서도 활성화 옵션이 존재합니다.
[코드 보여줘] z. AopContextWay
만약에 익스포즈프록시 옵션을 사용하실 수 없는 환경이라면, 셀프방법을 사용하셔야되는데요.
#85 셀프 방법이 뭐냐하면
바로 IoC 컨테이너에 등록된 자기 자신의 빈을 활용하는 방법인데요.
코드를 잠시보자면
[코드 보여줘] g. IoCContainerWay
[1] 먼저 자기 자신을 DI 해줍니다. 이는 자기 자신의 복사본을 만드신다고 생각하시면 될거 같아요.
[2] 메써드는 자기 자신의 주입된 빈을 통해 호출을 하시면 되는데요.
#86 하지만 아무래도 Proxy를 기반으로 하고 있기 때문에,
Self invocation을 처리하기 위해 코드를 추가한다는건 번거로운 작업이고 심지어 코드가 이질감이 느껴지는데요.
마지막으로 소개할 방법은 Spring AOP의 Weaving 방식을 AspectJ Weaving 방식으로 바꾸면 되는데요.
#87 AspectJ Weaving은 Spring AOP와 달리 바이트 코드를 조작하는 방식이기 때문에
Proxy의 Self-Invocation 이슈가 발생하지 않습니다.
따라서 Self-Invocation를 해결하기 위해 기존 코드를 수정하는 작업이 필요하지 않죠.
#88 AspectJ의 위빙 방식으로 설정하기 위해선 다음과 같이 3 가지 조건이 필요한데요.
첫 번째는 아무래도 AspectJ 파일이 필요합니다.
두 번째는 AspectJ의 위버라는 애가 필요하구요
마지막으론 AspectJ는 별도의 AspectJ 컴파일러가 필요합니다.
Weaver와 Compiler 사용하기 위해선 의존성에 추가 해주셔야 되는데요.
#89 다음 두 라이브러리는 반드시 의존성을 추가해줘야합니다 .
위버 라이브러리는 많이들 보셨을 텐데,
Spring AOP에서
@AspectJ 스타일 방식을 사용하기 위해선 반드시 추가해줘야할 라이브러리인데요.
Spring AOP에서 @AspectJ를 쓰는 이유가 단순히 편의성만은 아닙니다.
바로 Weaving 방식을 쉽게 바꿀 수 있기 때문입니다.
따라서 기존에 작성하였던 Aspect 자바 파일을 그대로 사용하시면 됩니다
#90 마지막으로 설정을 해주셔야 되는데요.
AspectJ는 AspectJ Compiler에 의해 Weaving을 처리하기 때문에,
이클립스에서 지원하는 AspectJ Development Tool을 사용하여 개발을 해야 됩니다.
하지만 미리 개발이 되었거나 상황이 안된다면, Mojo의 AspectJ Maven Plugin을 사용하면 됩니다.
샘플 코드를 보여드리자면
[코드 보여줘] ctw
마지막으로 바이트 코드가 조작됐는지 확인해보겠습니다.
#91 다음 클래스 파일을 보시면 AspectJ에 의해 바이트 코드가 조작되어있다는걸 확인하실 수 있는데요.
AspectJ Weaving으로 설정되면 Spring은 Proxy 방식이 아닌 바이트 코드가 조작된 코드 자체가 실행이 됩니다.
마지막으로 성능에 대해 살펴보자면..
#92 다음과 같은데요.
이 성능표는 Spring Blog에서도 소개되었던 공식적인 데이터라고 할 수 있습니다.
다음 수치는 실행시간을 측정한 결과입니다. 따라서 수치가 낮을수록 빠르다고 보시면 되겠습니다.
당연한 결과이지만 AspectJ와 Spring AOP에 대해
성능 비교를 해보았을 때 10배에서 30배까지
성능 차이가 난다는걸 확인해보실 수 있습니다.
https://web.archive.org/web/20150520175004/https://docs.codehaus.org/display/AW/AOP+Benchmark – 성능
#93 그렇다면 성능이 좋은 AspectJ로 개발을 하지,
왜 Spring AOP를 사용해야될까 라는 고민이 생기실꺼에요.
하지만 Spring AOP가 주는 장점을 버릴 수 없는거죠.
대표적인 예가 바로 IoC 컨테이너에 존재하는 빈에 대해 AOP를 쉽게 구현할 수 있다는 점이에요.
#94 무슨말인가 하면
빈은 기본적으로 하나의 POJO객체에 여러 프로퍼티가 포함하고 있는데요.
Spring AOP는 빈이 생성된 시점에 BPP를 활용하여 AOP를 쉽게 구현해주고 있습니다.
하지만 순수 AspectJ로 구현하기 위해선 이 시점들을
바이트 코드로 제어하기가 상당히 번거롭다는 단점이 생깁니다.
따라서 적적히 분배하여 사용해야됩니다.
#95 지금까지 배웠던 내용을 다시 정리해보자면
프록시 디자인 패턴에서 메소드 단위로 위임코드가 수행된다는걸 알 수 있었구요.
JDK Dynamic Proxy가 인터페이스 구조로 되어있다는거 알 수 있었고,
여러 핸들러 관리할 수 없었기 때문에 Spring AOP에선 Advisor라는 개념이 나왔구요.
또한, Bean Post Process를 통해 AutoProxing이 구현되는걸 볼 수 있었고 이러한 방식이 Spring의 AOP 메커니즘이라는점
그리고 JDK Dynamic Proxy와 Cglib을 비교하여 생성의 차이에대해 알아보았습니다.
마지막으로 Self Invocation을 해결보았습니다.