[Spring] ProxyFactory

2022. 6. 3. 11:01ใ†๐ŸŒฟ Spring

 

์ด์ „ ํฌ์ŠคํŒ…์—์„œ ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•  ๋•Œ์˜ ๋ฌธ์ œ์ ์„ ์งš์–ด๋ดค๋‹ค.

 

  1. ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” CGLIB๋ฅผ, ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” JDK ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•ด์•ผํ•œ๋‹ค.
  2. ๋‘ ๊ธฐ์ˆ ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, JDK ๋™์  ํ”„๋ก์‹œ์˜ InvocationHandler ์™€ CGLIB์˜ MethodInterceptor๋ฅผ ์ค‘๋ณตํ•ด์„œ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌํ•ด์•ผํ• ๊นŒ?
  3. ํŠน์ • ์กฐ๊ฑด์—์„œ(ํ•„ํ„ฐ) ํ”„๋ก์‹œ ๋กœ์ง์„ ์ ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ณตํ†ต์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. 

 

์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” ์ถ”์ƒํ™”๋œ ํ”„๋ก์‹œ ๊ธฐ์ˆ  : ProxyFactory 

์Šคํ”„๋ง์€ ๋™์  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ์ƒ์„ฑํ•ด ์ฃผ๋Š” ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ(Proxy Factory) ๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด์ „์—๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ ์œ ๋ฌด์— ๋”ฐ๋ผ JDK ๋™์  ํ”„๋ก์‹œ๋‚˜ CGLIB ์„ ์„ ํƒํ•ด์•ผ ํ–ˆ๋‹ค๋ฉด, ์ด์ œ๋Š” Proxy Factory ํ•˜๋‚˜๋กœ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. Proxy Factory ์˜ ์˜์กด ๊ด€๊ณ„์™€ ์‚ฌ์šฉ ํ๋ฆ„์€ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™๋‹ค. 

 

Advice , Pointcut ๋„์ž…

์Šคํ”„๋ง์€ Advice ๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ๋„์ž…ํ•˜๋ฉด์„œ, ์ƒํ™ฉ์— ๋”ฐ๋ผ JDK ๋™์ ํ”„๋ก์‹œ๋‚˜ CGLIB ๋ฅผ ๋”ฐ๋กœ ์ƒ์„ฑํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” InvocationHandler ๋‚˜ MethodInterceptor ๋ฅผ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ , Advice ๋งŒ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค. ( Advice ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ ์šฉํ•˜๊ณ  ์‹ถ์€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง์ด๋ผ ์ƒ๊ฐํ•˜์ž )

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋‚ด๋ถ€์—์„œ Advice ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ „์šฉ InvocationHandler, MethodInterceptor ๋ฅผ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.

์ด์ „์— FilterHandler ๋ฅผ ๋งŒ๋“ค์–ด, ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ๋ฉ”์„œ๋“œ์—๋งŒ ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•œ ์ ์ด ์žˆ๋‹ค. ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ์—์„œ๋Š” Pointcut ์ด๋ผ๋Š” ๊ฐœ๋…์„ ๋„์ž…ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ํ•ด๊ฒฐํ•œ๋‹ค. ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ Advice ์™€ Pointcut ์„ ๋” ์ดํ•ดํ•ด๋ณด์ž. 

 

 

 

Advice, Pointcut ์˜ˆ์ œ ์ฝ”๋“œ

Advice ๋Š” ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๋กœ์ง์„ ๋‹ด๋‹นํ•œ๋‹ค๊ณ  ํ–ˆ๋‹ค. ์—ฌ๊ธฐ์„œ TimeAdvice ๋Š” ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ฒดํฌํ•˜์—ฌ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•œ๋‹ค. Advice ๋Š” MethodInterceptor ๋ฅผ ์ƒ์†๋ฐ›์•„ invoke(MethodInvocation invocation) ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•˜๋Š”๋ฐ, ์ด ๋•Œ invocation.proceed() ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด targe ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ด๋ฐ›๋Š”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด์ „ ํฌ์ŠคํŒ…๊ณผ ๋‹ฌ๋ฆฌ target ์˜ ์ •๋ณด๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค. ์ด์ „์—๋Š” ์ƒ์„ฑ์ž๋กœ target ์„ ์ฃผ์ž…๋ฐ›์•˜์ง€๋งŒ, MethodInterceptor ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, MethodInvocation invocation ๋‚ด๋ถ€์— target ์˜ ํด๋ž˜์Šค ์ •๋ณด๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋ผ ์žˆ๋‹ค.

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

@Slf4j
public class TimeAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        log.info("TimeProxy ์‹คํ–‰");
        long startTime = System.currentTimeMillis();
        
        // ๊ธฐ์กด
        //Object result = method.invoke(target, args); 

        // ๋ณ€๊ฒฝ : MethodInterceptor ์ƒ์† ํ›„ 
        Object result = invocation.proceed(); 
        // target ์„ ์ž๋™์œผ๋กœ ์ฐพ๊ณ  ์ธ์ž๋ฅผ ๋„˜๊ธด๋‹ค. -> ์‹ค์ œ ํƒ€๊ฒŸ์„ ํ˜ธ์ถœํ•œ๋‹ค.

        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeProxy ์ข…๋ฃŒ resultTime={}", resultTime);
        return result;
    }
}

์ฃผ์˜ํ•  ์ ์€, TimeAdvice ๊ฐ€ ์ƒ์†๋ฐ›๋Š” MethodInterceptor ๊ฐ€ CGLIB์˜ MethodInterceptor ์™€ ์ด๋ฆ„์ด ๊ฐ™์œผ๋ฏ€๋กœ ํŒจํ‚ค์ง€ ์ด๋ฆ„์— ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค. Advice ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” org.aopalliance.intercept ์Šคํ”„๋ง AOP ๋ชจ๋“ˆ ๋‚ด๋ถ€์— ์žˆ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•œ๋‹ค.

์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Advice ๋ฅผ ProxyFactory ์— ์ „๋‹ฌํ•˜๋ฉด proxy ๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ณ  ์ ์šฉ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Advice - ProxyFactory ์ ์šฉ  (1) : ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” target ์˜ proxy ์ƒ์„ฑ

  • ์šฐ์„  Proxy ๋ฅผ ์ ์šฉํ•  ๋Œ€์ƒ (target) ๊ฐ์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ServiceInterface ํƒ€์ž…์˜ ServiceImpl ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ target ์œผ๋กœ ์ง€์ •ํ–ˆ๋‹ค. ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ์Œ์„ ์ธ์ง€ํ•˜์ž
  • ๊ทธ ๋‹ค์Œ ProxyFactory() ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ธ์ž๋กœ target ๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค. ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋Š” ์ด ์ธ์Šคํ„ด์Šค ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ด๋ถ€์—์„œ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 
  • ์šฐ๋ฆฌ๊ฐ€ ๋„˜๊ฒจ์ค€ ์ธ์Šคํ„ด์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์•˜๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ๋‹ค. ์ฆ‰ target ์ธ์Šคํ„ด์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ProxyFactory ๋‚ด๋ถ€์—์„œ JDK ๋™์  ํ”„๋ก์‹œ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด CGLIB ๋ฅผ ํ†ตํ•ด ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 
  • proxyFactory.addAdvice() : ์ด์ œ ํ”„๋ก์‹œ๊ฐ€ ์‚ฌ์šฉํ•  ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๋กœ์ง์„ addAdvice() ์˜ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค€๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  TimeAdvice ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋„˜๊ฒจ์ฃผ์ž.  ( JDK ๋™์  ํ”„๋ก์‹œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” InvocationHandler ์™€ CGLIB๊ฐ€ ์ œ๊ณตํ•˜๋Š” MethodInterceptor์˜ ๊ฐœ๋…๊ณผ ์œ ์‚ฌ)
  • ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๊นŒ์ง€ ์„ค์ •์„ ๋งˆ์นœ proxyFactory ๋Š” proxyFactory.getProxy() ๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š”๋‹ค. 
@Slf4j
public class ProxyFactoryTest {

    @Test
    @DisplayName("์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด JDK ๋™์  ํ”„๋ก์‹œ ์‚ฌ์šฉ")
    void interfaceProxy() {
    
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);  
        // target ์„ ๋„ฃ์œผ๋ฉด์„œ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ ๋‹ค. ์ฆ‰ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋Š” ์ด๋ฏธ ํƒ€๊ฒŸ์˜ ์ •๋ณด๋ฅผ ์•Œ๊ณ ์žˆ๋‹ค.
        // ํ”„๋ก์‹œ์˜ ํ˜ธ์ถœ๋Œ€์ƒ(target)์„ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ธ์ž๋กœ ๋„˜๊ธฐ๋Š” ๊ฒƒ.

        proxyFactory.addAdvice(new TimeAdvice());  // advice ์ถ”๊ฐ€ -> ํ”„๋ก์‹œ๊ฐ€ ์‚ฌ์šฉํ•  ๋ถ€๊ฐ€ ๋กœ์ง์„ ์„ค์ •ํ•œ๋‹ค. (advice : ์กฐ์–ธ์„ ํ•ด์ค€๋‹ค.)
        ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());
        
        proxy.save(); // ํ”„๋ก์‹œ ๊ฐ์ฒด์˜ ์ž์ฒด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, advice ๋กœ ์ถ”๊ฐ€๋œ (๋กœ๊ทธ) ๋กœ์ง์ด ์ˆ˜ํ–‰๋œ๋‹ค.
        // save() ์— ์ •์˜๋œ "save ํ˜ธ์ถœ" ์ด๋ž€ ๋กœ๊ทธ๊ฐ€ ๋ฐ”๋กœ ์ฐํžˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, TimeAdvice() ๋‚ด๋ถ€์—์„œ invocation.proceed() ํ•  ๋•Œ save()์˜ ๋กœ๊ทธ๊ฐ€ ์ฐํžŒ๋‹ค,.
        
        assertThat(AopUtils.isAopProxy(proxy)).isTrue();
        assertThat(AopUtils.isJdkDynamicProxy(proxy)).isTrue();  // ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•˜๋ฏ€๋กœ JDK dynamic proxy
        assertThat(AopUtils.isCglibProxy(proxy)).isFalse();

    }
}

 

์‹คํ–‰ ๊ฒฐ๊ณผ

 

 

Advice - ProxyFactory ์ ์šฉ  (2) : ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋ก์‹œ ์ƒ์„ฑ

(1) ์˜ˆ์ œ ์ฝ”๋“œ์™€ ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง„ ๊ฒƒ์€ ์—†๋‹ค. ์ฐจ์ด์ ์ด๋ผ๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๋Š” ๊ตฌ์ฒดํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋˜‘๊ฐ™์ด ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ , ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž. 

@Slf4j
public class ProxyFactoryTest {

    @Test
    @DisplayName("๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ์žˆ์œผ๋ฉด CGLIB ์‚ฌ์šฉ")
    void concreteProxy() {
        ConcreteService target = new ConcreteService();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        proxyFactory.addAdvice(new TimeAdvice());
        ConcreteService proxy = (ConcreteService) proxyFactory.getProxy();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());

        proxy.call();

        assertThat(AopUtils.isAopProxy(proxy)).isTrue();
        assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse();
        assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
    }

}

assertThat(AopUtils.isCglibProxy(proxy)).isTrue() ๊ฐ€ ํ†ต๊ณผํ•˜๋Š” ๊ฒƒ์„ ๋ณด์•„ CGLIB ๋ฅผ ํ™œ์šฉํ•ด ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

Advice - ProxyFactory ์ ์šฉ  (3) : ProxyTargetClass ์˜ต์…˜ ์‚ฌ์šฉ

target ์ธ์Šคํ„ด์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์ง€๋งŒ, setProxyTargetClass(true) ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด JDK ๋™์  ํ”„๋ก์‹œ ๋Œ€์‹  ๊ฐ•์ œ๋กœ CGLIB ๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

@Slf4j
public class ProxyFactoryTest {

    @Test
    @DisplayName("ProxyTargetClass ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์–ด๋„ CGLIB๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ์‚ฌ์šฉ")
    void proxyTargetClass() {
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        
        proxyFactory.setProxyTargetClass(true); 
        // proxy ๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ target ํด๋ž˜์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค๊บผ์•ผ! ๋ผ๊ณ  ์„ค์ •
        
        proxyFactory.addAdvice(new TimeAdvice());
        ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());

        proxy.save();

        assertThat(AopUtils.isAopProxy(proxy)).isTrue();
        assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse();
        assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
    }

}

 

์ •๋ฆฌ

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ์˜ ์ถ”์ƒํ™” ๋•๋ถ„์— ๊ตฌ์ฒด์ ์ธ CGLIB, JDK ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋๋‹ค. ๋˜ํ•œ ํ”„๋ก์‹œ์˜ ๋ถ€๊ฐ€๊ธฐ๋Šฅ ๋กœ์ง๋„ ํŠน์ • ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๊ณ , Advice ํ•˜๋‚˜๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด๊ฒƒ์€ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ ๋‚ด๋ถ€์—์„œ JDK ๋™์  ํ”„๋ก์‹œ์ธ ๊ฒฝ์šฐ InvocationHandler ๊ฐ€  Advice ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , CGLIB ์ธ ๊ฒฝ์šฐ MethodInterceptor ๊ฐ€ Advice ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ๊ฐœ๋ฐœ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค .

 

 

์ฝ”๋“œ ๋ฐ ์ž๋ฃŒ ์ถœ์ฒ˜

 

์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ณ ๊ธ‰ํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋“ค์„ ๊นŠ์ด์žˆ๊ฒŒ ํ•™์Šตํ•˜๊ณ , ์Šคํ”„๋ง์„ ์ž์‹ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com