Spring

[Spring] AOP λ™μž‘μ›λ¦¬ : λ¦¬ν”Œλ ‰μ…˜, JDK 동적 ν”„λ‘μ‹œ

sian han 2025. 6. 12. 17:18

πŸŽ“ 이 글은 μΈν”„λŸ°μ—μ„œ μ œκ³΅ν•˜λŠ” "μŠ€ν”„λ§ ν•΅μ‹¬ μ›λ¦¬ - κ³ κΈ‰νŽΈ" κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜λ©΄μ„œ μ •λ¦¬ν•œ λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ μž‘μ„±ν•œ κΈ€μž…λ‹ˆλ‹€.

https://inf.run/FWeFN

 

이전글 μ—μ„œ ν”„λ‘μ‹œλ₯Ό μ‚¬μš©ν•΄μ„œ κΈ°μ‘΄ μ½”λ“œλ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³  λΆ€κ°€κΈ°λŠ₯을 μ μš©ν•˜λŠ” 방법을 μ•Œμ•„λ΄€λ‹€. κ·ΈλŸ¬λ‚˜ 클래슀 기반 ν”„λ‘μ‹œμ˜ 경우 λΆ€κ°€κΈ°λŠ₯을 μ μš©ν•΄μ•Ό ν•˜λŠ” λŒ€μƒ ν΄λž˜μŠ€κ°€ 100개라면 ν”„λ‘μ‹œ ν΄λž˜μŠ€λ„ 100개 λ§Œλ“€μ–΄μ•Ό ν–ˆλ‹€. ν”„λ‘μ‹œ 클래슀λ₯Ό ν•˜λ‚˜λ§Œ λ§Œλ“€μ–΄μ„œ λͺ¨λ“  곳에 μ μš©ν•  μˆ˜λŠ” μ—†μ„κΉŒ ? 

 

μžλ°”κ°€ 기본으둜 μ œκ³΅ν•˜λŠ” JDK 동적 ν”„λ‘μ‹œ κΈ°μˆ μ„ ν™œμš©ν•˜λ©΄ ν”„λ‘μ‹œ 객체λ₯Ό λ™μ μœΌλ‘œ λ§Œλ“€μ–΄λ‚Ό 수 μžˆλ‹€. 

JDK 동적 ν”„λ‘μ‹œλ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ¨Όμ € μžλ°”μ˜ λ¦¬ν”Œλ ‰μ…˜ κΈ°μˆ μ„ 이해해야 ν•œλ‹€. 

 

β€» λ¦¬ν”Œλ ‰μ…˜ 기술

  • λ¦¬ν”Œλ ‰μ…˜ κΈ°μˆ μ„ 톡해 ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ˜ 메타정보λ₯Ό λ™μ μœΌλ‘œ νšλ“ν•  수 μžˆλ‹€
  • λ¦¬ν”Œλ ‰μ…˜ κΈ°μˆ μ„ 톡해 μ½”λ“œλ₯Ό λ™μ μœΌλ‘œ ν˜ΈμΆœν•  수 μžˆλ‹€

λ¨Όμ € μ•„λž˜ μ½”λ“œλ₯Ό 보자

@Test
void reflection0() {
    Hello target = new Hello();

    //곡톡 둜직1 μ‹œμž‘
    log.info("start");
    String result1 = target.callA(); //ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œκ°€ λ‹€μŒ
    log.info("result={}", result1);
    //곡톡 둜직1 μ’…λ£Œ

    //곡톡 둜직2 μ‹œμž‘
    log.info("start");
    String result2 = target.callB(); //ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œκ°€ λ‹€μŒ
    log.info("result={}", result2);
    //곡톡 둜직2 μ’…λ£Œ
}

 

κ³΅ν†΅λ‘œμ§ 1κ³Ό 2λŠ” ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œλ§Œ λ‹€λ₯΄κ³  전체 μ½”λ“œ 흐름이 μ™„μ „ κ°™λ‹€.

μ—¬κΈ°μ„œ 곡톡 둜직 1κ³Ό 2λ₯Ό ν•˜λ‚˜μ˜ λ©”μ„œλ“œλ‘œ λ½‘μ•„μ„œ ν•©μΉ˜κ³  μ‹Άλ‹€.

쀑간에 ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œκ°€ λ‹€λ₯΄κΈ°λ•Œλ¬Έμ— μ‰¬μ›Œ λ³΄μ΄μ§€λ§Œ λ©”μ„œλ“œλ‘œ λ½‘μ•„μ„œ κ³΅ν†΅ν™”ν•˜λŠ” 것이 μ–΄λ ΅λ‹€. 

 

μ΄λ•Œ μ‚¬μš©ν•˜λŠ” 기술이 λ¦¬ν”Œλ ‰μ…˜μ΄λ‹€. 

λ¦¬ν”Œλ ‰μ…˜μ€ ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œμ˜ 메타정보λ₯Ό μ‚¬μš©ν•΄μ„œ λ™μ μœΌλ‘œ ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œλ₯Ό λ³€κ²½ν•  수 μžˆλ‹€. 

 

    @Test
    void reflection1() throws Exception {
        //클래슀 정보
        Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");

        Hello target = new Hello();
        //callA λ©”μ„œλ“œ 정보
        Method methodCallA = classHello.getMethod("callA");
        Object result1 = methodCallA.invoke(target);
        log.info("result1={}", result1);

        //callB λ©”μ„œλ“œ 정보
        Method methodCallB = classHello.getMethod("callB");
        Object result2 = methodCallB.invoke(target);
        log.info("result2={}", result2);
    }

 

  • Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
    • Class.forName(...) 은 클래슀 이름을 λ¬Έμžμ—΄λ‘œ λ°›μ•„μ„œ 클래슀λ₯Ό JVM 에 λ‘œλ”©ν•˜κ³  클래슀의 메타정보λ₯Ό λ°˜ν™˜ν•˜λŠ” 역할을 ν•œλ‹€. 
    • () μ•ˆμ—λŠ” νŒ¨ν‚€μ§€λͺ…λΆ€ν„° λ‚΄λΆ€ ν΄λž˜μŠ€κΉŒμ§€ ν¬ν•¨ν•œ "μ™„μ „ν•œ 클래슀 이름" 이 λ“€μ–΄κ°„λ‹€. 
    • 메타정보에 ν¬ν•¨λœ λ‚΄μš©μ€ ν΄λž˜μŠ€μ΄λ¦„, ν•„λ“œ 정보, λ©”μ„œλ“œ 정보, μƒμ„±μžμ •λ³΄, μƒμœ„ν΄λž˜μŠ€ 등이 μžˆλ‹€. 

classHello.getMethod("A") λ₯Ό 톡해 λ©”μ„œλ“œ 메타정보λ₯Ό νšλ“ν•œ λ’€, methodCallA 에 ν• λ‹Ήν•œλ‹€.

methodCallA.invoke(μΈμŠ€ν„΄μŠ€) λŠ” μ§€μ •ν•œ μΈμŠ€ν„΄μŠ€(target)의 λ©”μ„œλ“œ(A)λ₯Ό μ‹€ν•Όν•  수 있게 ν•œλ‹€.

μ΄λ ‡κ²Œ ν•˜λ©΄ λ©”μ„œλ“œ 정보λ₯Ό λ™μ μœΌλ‘œ λ³€κ²½ν•  수 있게 λœλ‹€. 

 

λ©”μ„œλ“œ 호좜 λΆ€λΆ„ κ³΅ν†΅λ‘œμ§μœΌλ‘œ 뢄리해내기

   @Test
    void reflection2() throws Exception {
        //클래슀 정보
        Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");

        Hello target = new Hello();
        Method methodCallA = classHello.getMethod("callA");
        dynamicCall(methodCallA, target);

        Method methodCallB = classHello.getMethod("callB");
        dynamicCall(methodCallB, target);
    }
    
    private void dynamicCall(Method method, Object target) throws Exception {
        log.info("start");
        Object result = method.invoke(target);
        log.info("result={}", result);
    }

 

 

  • dynamicCall(Method method, Object target)
    • κ³΅ν†΅λ‘œμ§ 1,2 λ₯Ό ν•œλ²ˆμ— μ²˜λ¦¬ν•  수 μžˆλŠ” ν†΅ν•©λœ 곡톡 처리 λ‘œμ§μ΄λ‹€. 
    • Method method : 첫번째 νŒŒλΌλ―Έν„°λŠ” ν˜ΈμΆœν•  λ©”μ„œλ“œ 정보가 λ„˜μ–΄μ˜¨λ‹€. κΈ°μ‘΄μ—λŠ” λ©”μ„œλ“œ 이름을 직접 ν˜ΈμΆœν–ˆμ§€λ§Œ μ΄μ œλŠ” Method 메타정보λ₯Ό ν†΅ν•΄μ„œ ν˜ΈμΆœν•  λ©”μ„œλ“œ 정보가 λ™μ μœΌλ‘œ μ œκ³΅λœλ‹€. 
    • Object target : μ‹€μ œ μ‹€ν–‰ν•  μΈμŠ€ν„΄μŠ€ 정보가 λ„˜μ–΄μ˜¨λ‹€. νƒ€μž…μ΄ Object 이기 λ•Œλ¬Έμ— μ–΄λ– ν•œ μΈμŠ€ν„΄μŠ€λ„ 받을 수 μžˆλ‹€. 
    • 주의 ! λ‹Ήν˜„νžˆ method.invode(target) 을 μ‚¬μš©ν•  λ•Œ ν˜ΈμΆœν•  ν΄λž˜μŠ€μ™€ λ©”μ„œλ“œ 정보가 λ‹€λ₯΄λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€. 

 

Q. λ©”μ„œλ“œ 호좜 λΆ€λΆ„λ§Œ λ‹€λ₯Έ 곡톡 둜직이 μžˆμ„λ•Œ, 이λ₯Ό κ°œμ„ ν•˜λŠ” 방법은 무엇이 μžˆμ„κΉŒμš” ?

 

β–Ά A. λ©”μ„œλ“œ 호좜 λΆ€λΆ„λ§Œ λ‹€λ₯Έ 곡톡 둜직이 μžˆλ‹€λ©΄, λ¦¬ν”Œλ ‰μ…˜ κΈ°μˆ μ„ ν™œμš©ν•΄ Method λΌλŠ” 메타정보 객체둜 μΆ”μƒν™”ν•˜μ—¬ 곡톡 λ‘œμ§μ„ ν•˜λ‚˜λ‘œ 톡합할 수 μžˆμŠ΅λ‹ˆλ‹€. λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄, ν˜ΈμΆœν•  λ©”μ„œλ“œλ₯Ό λ¬Έμžμ—΄λ‘œ μ§€μ •ν•˜μ—¬ Method 객체둜 μ–»κ³ , 이λ₯Ό 톡해 μ‹€μ œ μΈμŠ€ν„΄μŠ€μ— λŒ€ν•΄ λ™μ μœΌλ‘œ λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이와 같이 λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄ ν΄λž˜μŠ€μ™€ λ©”μ„œλ“œμ˜ 메타 정보λ₯Ό μ‚¬μš©ν•΄μ„œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ™μ μœΌλ‘œ μœ μ—°ν•˜κ²Œ λ§Œλ“€ 수 μžˆμ§€λ§Œ, λ¦¬ν”Œλ ‰μ…˜ κΈ°μˆ μ€ λŸ°νƒ€μž„μ— λ™μž‘ν•˜κΈ° λ•Œλ¬Έμ— 컴파일 μ‹œμ μ— 였λ₯˜λ₯Ό μž‘μ„ 수 μ—†μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μΌλ°˜μ μœΌλ‘œλŠ” ꢌμž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

 

 

β€» JDK 동적 ν”„λ‘μ‹œ

JDK 동적 ν”„λ‘μ‹œλ₯Ό μ•ŒκΈ° μœ„ν•΄ λ¨Όμ € λ¦¬ν”Œλ ‰μ…˜μ„ μ•Œμ•„λ΄€λ‹€. 

μ•žμ„œμ„œλŠ” κ°œλ°œμžκ°€ 직접 ν”„λ‘μ‹œ 클래슀λ₯Ό λ§Œλ“€μ–΄ 문제λ₯Ό ν•΄κ²°ν–ˆμ—ˆλ‹€ (ν”„λ‘μ‹œ νŒ¨ν„΄, λ°μ½”λ ˆμ΄ν„° νŒ¨ν„΄)

동적 ν”„λ‘μ‹œ κΈ°μˆ μ„ μ‚¬μš©ν•˜λ©΄ κ°œλ°œμžκ°€ 직접 ν”„λ‘μ‹œ 클래슀λ₯Ό λ§Œλ“€μ§€ μ•Šμ•„λ„ λœλ‹€(JVM 이 ν”„λ‘μ‹œ 클래슀λ₯Ό λŸ°νƒ€μž„μ— λ™μ μœΌλ‘œ 생성해주기 λ•Œλ¬Έ) 동적 ν”„λ‘μ‹œ κΈ°μˆ μ€ ν”„λ‘μ‹œ 객체λ₯Ό λ™μ μœΌλ‘œ λŸ°νƒ€μž„μ— 개발자 λŒ€μ‹  λ§Œλ“€μ–΄μ€€λ‹€. κ°œλ°œμžλŠ” 동적 ν”„λ‘μ‹œμ— μ›ν•˜λŠ” μ‹€ν–‰ λ‘œμ§μ„ μ§€μ •ν•  수 μžˆλ‹€. JDK 동적 ν”„λ‘μ‹œλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό 기반으둜 ν”„λ‘μ‹œλ₯Ό λ™μ μœΌλ‘œ λ§Œλ“€μ–΄μ€€λ‹€. λ”°λΌμ„œ μΈν„°νŽ˜μ΄μŠ€κ°€ ν•„μˆ˜μ΄λ‹€. 

 

β–Ά 동적 ν”„λ‘μ‹œμ˜ ꡬ성

public interface AInterface {
    String call();
}
public class AImpl implements AInterface {
    @Override
    public String call() {
        log.info("A 호좜");
        return "a";
    }
}
public interface BInterface {
    String call();
}
public class BImpl implements BInterface {
    @Override
    public String call() {
        log.info("B 호좜");
        return "b";
    }
}

 

 

⭐️⭐️⭐️ JDK 동적 ν”„λ‘μ‹œμ— μ μš©ν•  λ‘œμ§μ€ λ°˜λ“œμ‹œ InvocationHandler μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ„œ μ œκ³΅ν•΄μ•Ό ν•œλ‹€ β­οΈβ­οΈβ­οΈ

ν•Έλ“€λŸ¬λŠ” 이 μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ κ°μ²΄μ—¬μ•Όλ§Œ ν”„λ‘μ‹œκ°€ λ™μž‘ν•  수 μžˆλ‹€. ν”„λ‘μ‹œκ°€ κ°€λ‘œμ±Œ λ©”μ„œλ“œ λ‘œμ§μ€ invoke() 내뢀에 μ •μ˜ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ΄λ‹€(invoke()λŠ” InvocationHandler의 κ΅¬ν˜„ λ©”μ„œλ“œμž„)

public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
  • InvocationHandler λŠ” JDK 동적 ν”„λ‘μ‹œμ—μ„œ λ©”μ„œλ“œ ν˜ΈμΆœμ„ κ°€λ‘œμ±„λŠ” ν•Έλ“€λŸ¬ μΈν„°νŽ˜μ΄μŠ€λ‘œ, ν”„λ‘μ‹œ 객체의 λ©”μ„œλ“œκ°€ 호좜될 λ•Œ μ‹€μ œ κ΅¬ν˜„μ²΄ λŒ€μ‹  이 ν•Έλ“€λŸ¬μ˜ invoke() λ©”μ„œλ“œκ°€ 싀행됨
    • proxy : ν”„λ‘μ‹œ 객체 μžμ‹ 
    • method : 호좜된 λ©”μ„œλ“œ(메타정보)
    • args : μ „λ‹¬λœ 인자
    • 리턴값 : μ›λž˜ λ©”μ„œλ“œμ˜ μ‹€ν–‰κ²°κ³Ό

InvocationHandler λ₯Ό κ΅¬ν˜„ν•œ TimeInvocationHandler

public class TimeInvocationHandler implements InvocationHandler {

    private final Object target;

    public TimeInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("TimeProxy μ‹€ν–‰");
        long startTime = System.currentTimeMillis();

        Object result = method.invoke(target, args);

        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeProxy μ’…λ£Œ resultTime={}", resultTime);
        return result;
    }
}

 

  • Object result = method.invoke(target, args) : target μΈμŠ€ν„΄μŠ€μ˜ method λ₯Ό μ‹€ν–‰ν•΄(invoke) !!! λΌλŠ” 뜻

 

 

β–Ά 동적 ν”„λ‘μ‹œμ˜ μ‚¬μš©

public class JdkDynamicProxyTest {

    @Test
    void dynamicA() {
        AInterface target = new AImpl();
        TimeInvocationHandler handler = new TimeInvocationHandler(target);

        AInterface proxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]{AInterface.class}, handler);

        proxy.call();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());
    }

    @Test
    void dynamicB() {
        BInterface target = new BImpl();
        TimeInvocationHandler handler = new TimeInvocationHandler(target);

        BInterface proxy = (BInterface) Proxy.newProxyInstance(BInterface.class.getClassLoader(), new Class[]{BInterface.class}, handler);

        proxy.call();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());
    }
}

 

μœ„ μ½”λ“œμ—μ„œ JDK 동적 ν”„λ‘μ‹œλ₯Ό μƒμ„±ν•˜λŠ” ν•΅μ‹¬μ½”λ“œ

AInterface proxy = (AInterface) Proxy.newProxyInstance(
    AInterface.class.getClassLoader(),     // β‘  클래슀 λ‘œλ”
    new Class[]{AInterface.class},         // β‘‘ ν”„λ‘μ‹œκ°€ κ΅¬ν˜„ν•  μΈν„°νŽ˜μ΄μŠ€ λͺ©λ‘
    handler                                // β‘’ λ©”μ„œλ“œ ν˜ΈμΆœμ„ κ°€λ‘œμ±Œ InvocationHandler κ΅¬ν˜„μ²΄
);

 

  • β‘  ν΄λž˜μŠ€ λ‘œλ” : ν”„λ‘μ‹œ κ°μ²΄λ„ JVM μ•ˆμ—μ„œ Class λ‘œ μƒμ„±λ˜λ―€λ‘œ, JVM μ΄ λ‘œλ”©ν• λ•Œ ν΄λž˜μŠ€ λ‘œλ”κ°€ ν•„μš”ν•œλ°, μ΄λ₯Ό λ„˜κ²¨μ€Œ
  • β‘‘ ν”„λ‘μ‹œκ°€ κ΅¬ν˜„ν•  μΈν„°νŽ˜μ΄μŠ€ λͺ©λ‘ : λ™μ  ν”„λ‘μ‹œλŠ” μΈν„°νŽ˜μ΄μŠ€ κΈ°λ°˜μ΄λ―€λ‘œ, μ—¬κΈ°μ„œ μ–΄λ–€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Όν• μ§€λ₯Ό λͺ…μ‹œν•΄μ€Œ
  • β‘’ λ©”μ„œλ“œ ν˜ΈμΆœμ„ κ°€λ‘œμ±Œ InvocationHandler κ΅¬ν˜„체 : λͺ¨λ“  λ©”μ„œλ“œ ν˜ΈμΆœμ€ μ΄ handler.invoke(proxy, method, args) λ‘œ μœ„μž„λ¨

μ΄λ ‡κ²Œ μƒμ„±λœ AInterface proxy λŠ” AInterface λ₯Ό κ΅¬ν˜„ν•˜κ³  있으며,

proxy.call() λ©”μ„œλ“œ 호좜 μ‹œ 직접 AImpl 을 ν˜ΈμΆœν•˜λŠ” 것이 μ•„λ‹ˆλΌ TimeInvocationHandler.invoke() λ‚΄λΆ€λ‘œ 흐름이 전달됨

 

μ‹€ν–‰μˆœμ„œ

  • 1. ν΄λΌμ΄μ–ΈνŠΈλŠ” JDK 동적 ν”„λ‘μ‹œμ˜ call()을 μ‹€ν–‰ν•œλ‹€
  • 2. JDK 동적 ν”„λ‘μ‹œλŠ” InvocationHandler.invoke() λ₯Ό ν˜ΈμΆœν•œλ‹€. TimeInvocationHandler κ°€ κ΅¬ν˜„μ²΄λ‘œ μžˆμœΌλ―€λ‘œ TimeInvocationHandler.invoke() κ°€ ν˜ΈμΆœλœλ‹€.
  • 3. TimeInvocationHandler κ°€ λ‚΄λΆ€ λ‘œμ§μ„ μˆ˜ν–‰ν•˜κ³ , method.invoke(target, args) λ₯Ό ν˜ΈμΆœν•΄μ„œ target인 μ‹€μ œ 객체(AImpl) λ₯Ό ν˜ΈμΆœν•œλ‹€.
  • 4. AImpl μΈμŠ€ν„΄μŠ€μ˜ call()이 μ‹€ν–‰λœλ‹€.
  • 5. AImpl μΈμŠ€ν„΄μŠ€μ˜ call()의 싀행이 λλ‚˜λ©΄ TimeInvocationHandler 둜 응닡이 λŒμ•„μ˜¨λ‹€. μ‹œκ°„λ‘œκ·Έλ₯Ό 좜λ ₯ν•˜κ³  κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. 

 

Q. λ©”μ„œλ“œ 호좜 λΆ€λΆ„λ§Œ λ‹€λ₯Έ 곡톡 둜직이 μžˆμ„λ•Œ, 이λ₯Ό κ°œμ„ ν•˜λŠ” 방법은 무엇이 μžˆμ„κΉŒμš” ?

 

β–Ά A . λ©”μ„œλ“œ 호좜 λΆ€λΆ„λ§Œ λ‹€λ₯Έ 곡톡 둜직이 λ°˜λ³΅λœλ‹€λ©΄, JDK 동적 ν”„λ‘μ‹œλ₯Ό ν™œμš©ν•΄ 곡톡 λ‘œμ§μ„ ν•˜λ‚˜μ˜ ν•Έλ“€λŸ¬λ‘œ 좔상화할 수 μžˆμŠ΅λ‹ˆλ‹€. 

λ§Œμ•½ 적용 λŒ€μƒμ΄ 100κ°œμ—¬λ„ 동적 ν”„λ‘μ‹œλ₯Ό ν†΅ν•΄μ„œ μƒμ„±ν•˜κ³  각각 ν•„μš”ν•œ InvocationHandler 만 λ§Œλ“€μ–΄μ„œ λ„£μ–΄μ£Όλ©΄ λ©λ‹ˆλ‹€. 

JDK 의 동적 ν”„λ‘μ‹œ κΈ°λŠ₯이 λŸ°νƒ€μž„μ— ν”„λ‘μ‹œ 객체λ₯Ό μžλ™μœΌλ‘œ 생성해주기 λ•Œλ¬Έμ—, κ°œλ°œμžλŠ” 곡톡 둜직만 ν•œ 곳에 μž‘μ„±ν•˜λ©΄ 되고, μ‹€μ œ λ©”μ„œλ“œ ν˜ΈμΆœμ€ λ™μ μœΌλ‘œ μœ„μž„μ΄ λ©λ‹ˆλ‹€. 

 

 

μ—¬κΈ°κΉŒμ§€ ν”„λ‘μ‹œ 객체가 λ©”μ„œλ“œλ₯Ό κ°€λ‘œμ±„κ³ , ν•Έλ“€λŸ¬μ—μ„œ 곡톡 λ‘œμ§μ„ μˆ˜ν–‰ν•œ λ’€ μ‹€μ œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” ꡬ쑰λ₯Ό κ²½ν—˜ν–ˆλŠ”λ°,

μŠ€ν”„λ§ AOP μ—­μ‹œ μ΄λŸ¬ν•œ ꡬ쑰(ν”„λ‘μ‹œ 기반 + λ©”μ„œλ“œ μœ„μž„)λ₯Ό λ°”νƒ•μœΌλ‘œ ν•΅μ‹¬ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 곡톡 관심사(예: νŠΈλžœμž­μ…˜, λ‘œκΉ…, λ³΄μ•ˆ λ“±)λ₯Ό  λΆ„λ¦¬ν•œλ‹€.