๊ด€๋ฆฌ ๋ฉ”๋‰ด

์‚ถ์˜ ๊ณต์œ 

[Spring] AOP ์™„๋ฒฝ ๊ฐ€์ด๋“œ ๋ณธ๋ฌธ

Web Dev/BackEnd

[Spring] AOP ์™„๋ฒฝ ๊ฐ€์ด๋“œ

dkrehd 2025. 4. 30. 22:39
728x90
๋ฐ˜์‘ํ˜•

๐ŸŒ€ Spring AOP ์™„๋ฒฝ ๊ฐ€์ด๋“œ: ์›๋ฆฌ, ์ˆ˜๋™/์ž๋™ ๊ตฌํ˜„ ๋น„๊ต ๋ถ„์„

๐Ÿ“Œ AOP(Aspect-Oriented Programming)๋ž€?

ํ•œ ์ค„ ์ •์˜
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๊ณตํ†ต๊ธฐ๋Šฅ(๋กœ๊น…, ํŠธ๋žœ์žญ์…˜, ๋ณด์•ˆ ๋“ฑ)์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•

AOP๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ(Cross-cutting Concerns)๋ฅผ ๋ถ„๋ฆฌํ•ด ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ํ•˜๊ณ  ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ค๋‹ˆ๋‹ค.


๐ŸŽฏ AOP๋Š” ์™œ ํ•„์š”ํ• ๊นŒ?

  • ์ค‘๋ณต ์ฝ”๋“œ ๊ฐ์†Œ
  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ ์ฆ๊ฐ€
  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋กœ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ๋ฐ ํ’ˆ์งˆ ํ–ฅ์ƒ
  • ํŠธ๋žœ์žญ์…˜, ๋กœ๊น…๊ณผ ๊ฐ™์€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์˜ ๊ด€๋ฆฌ ํŽธ๋ฆฌ์„ฑ ์ฆ๊ฐ€

 

 

๐Ÿš€ AOP ๊ตฌํ˜„ ๋ฐฉ์‹ ๋น„๊ต: ์ˆ˜๋™ vs ์ž๋™

๐Ÿ”ธ (1) AOP ์ˆ˜๋™ ๊ตฌํ˜„

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋กœ AOP๋ฅผ ํ‰๋‚ด ๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ Java์˜ Reflection API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠน์ • ๊ทœ์น™(๋ฉ”์„œ๋“œ ์ด๋ฆ„ ํŒจํ„ด, ์–ด๋…ธํ…Œ์ด์…˜ ๋“ฑ)์— ๋”ฐ๋ผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ(Advice)์„ ํ•ต์‹ฌ ๋กœ์ง ํ˜ธ์ถœ ์ „ํ›„์— ์‹คํ–‰์‹œํ‚ค๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

์˜ˆ์ œ ์ฝ”๋“œ ์‚ดํŽด๋ณด๊ธฐ:

  • MyClass.java: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. aaa(), aaa2(), bbb() ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. aaa() ๋ฉ”์„œ๋“œ์—๋Š” @Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • MyAdvice.java: ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ(Advice)์„ ๋‹ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
    • invoke() ๋ฉ”์„œ๋“œ: Reflection์œผ๋กœ ์–ป์–ด์˜จ Method ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„, ํŠน์ • ์กฐ๊ฑด(์—ฌ๊ธฐ์„œ๋Š” @Transactional ์–ด๋…ธํ…Œ์ด์…˜ ์œ ๋ฌด)์„ ๋งŒ์กฑํ•˜๋ฉด ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„์— ๊ณตํ†ต ์ฝ”๋“œ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ์‹ค์ œ ๋ฉ”์„œ๋“œ(m.invoke(obj, arg))๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
    • Pattern, matches(): (์˜ˆ์ œ์—์„œ๋Š” invoke ์กฐ๊ฑด๋ฌธ์—์„œ ์ฃผ์„ ์ฒ˜๋ฆฌ๋˜์—ˆ์ง€๋งŒ) ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ํŠน์ • ํŒจํ„ด("a"๋กœ ์‹œ์ž‘)๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ Advice ์ ์šฉ ๋Œ€์ƒ์„ ์„ ์ •ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•(Pointcut ์‹œ๋ฎฌ๋ ˆ์ด์…˜)์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
  • AopMain.java: Reflection์„ ์‚ฌ์šฉํ•˜์—ฌ MyClass์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ MyAdvice์˜ invoke ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
 
// AopMain.java (์ผ๋ถ€)
Class myClass = Class.forName("com.ABC.sbtch3.AOP.MyClass");
Object o = myClass.newInstance();
MyAdvice myAdvice = new MyAdvice();
for(Method m : myClass.getDeclaredMethods()){
    myAdvice.invoke(m, o, null); // ๊ฐ ๋ฉ”์„œ๋“œ๋ฅผ Advice๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ
}

// MyAdvice.java (์ผ๋ถ€)
class MyAdvice {
    // ... Pattern p, matches() ...

    void invoke(Method m, Object obj, Object... arg) throws Exception {
        // @Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด์žˆ๋Š” ๋ฉ”์„œ๋“œ์—๋งŒ ์ „/ํ›„ ๋ถ€๊ฐ€๊ธฐ๋Šฅ ์ ์šฉ (Pointcut ์—ญํ• )
        if(m.getAnnotation(Transactional.class)!= null) {
            System.out.println("[before]{"); // ๊ณตํ†ต ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ (Advice)
        }
        m.invoke(obj, arg); // ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ(ํ•ต์‹ฌ ๋กœ์ง) ํ˜ธ์ถœ
        if(m.getAnnotation(Transactional.class)!= null) {
            System.out.println("}[after]"); // ๊ณตํ†ต ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ (Advice)
        }
    }
}

// MyClass.java (์ผ๋ถ€)
class MyClass {
    @Transactional // ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ ์šฉ ๋Œ€์ƒ์ž„์„ ํ‘œ์‹œ
    void aaa() { System.out.println("aaa() is called"); }
    void aaa2() { System.out.println("aaa2() is called"); }
    void bbb() { System.out.println("bbb() is called"); }
}

์ฝ”๋“œ ๋ถ€์—ฐ ์„ค๋ช…:

  • invoke(Method m, Object obj, Object... arg): Reflection์˜ Method.invoke()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ ํƒ€๊ฒŸ ๊ฐ์ฒด(obj)์˜ ๋ฉ”์„œ๋“œ(m)๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ํ˜ธ์ถœ ์ „ํ›„์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์‚ฝ์ž…ํ•จ์œผ๋กœ์จ AOP์˜ 'Around Advice'์™€ ์œ ์‚ฌํ•œ ๋™์ž‘์„ ํ‰๋‚ด ๋ƒ…๋‹ˆ๋‹ค.
  • if(m.getAnnotation(Transactional.class)!= null): ์ด ์กฐ๊ฑด๋ฌธ์ด Pointcut (๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•  ๋Œ€์ƒ์„ ์„ ๋ณ„ํ•˜๋Š” ์กฐ๊ฑด)์˜ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” @Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋งŒ ๋Œ€์ƒ์œผ๋กœ ์‚ผ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋Š” ์—†์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘/์ข…๋ฃŒ ๋กœ์ง์ด ์ด๋Ÿฌํ•œ ํ˜•ํƒœ๋กœ ์ ์šฉ๋  ์ˆ˜ ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋Š” ๋Œ€ํ‘œ์ ์ธ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ(Cross-Cutting Concern) ์ด๋ฏ€๋กœ AOP ์ ์šฉ์— ๋งค์šฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • Pattern, matches(): ๋งŒ์•ฝ ์ด๋ฆ„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋Œ€์ƒ์„ ์„ ์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด matches(m)์™€ ๊ฐ™์€ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Pattern.compile("a.*")์€ 'a'๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜๋™ ๊ตฌํ˜„์˜ ํ•œ๊ณ„:

  • ๋ณต์žก์„ฑ: ๋ชจ๋“  ๊ฐ์ฒด์™€ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด Reflection ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋ฒˆ๊ฑฐ๋กญ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ ์ €ํ•˜: Reflection API๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๋А๋ฆฝ๋‹ˆ๋‹ค.
  • ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ: ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜์˜ ํด๋ž˜์Šค/๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์‚ฌ์šฉ, ํƒ€์ž… ์ฒดํฌ์˜ ์–ด๋ ค์›€ ๋“ฑ์œผ๋กœ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.
  • ์ œํ•œ์ ์ธ ๊ธฐ๋Šฅ: Pointcut ํ‘œํ˜„, ๋‹ค์–‘ํ•œ Advice ํƒ€์ž…(Before, After ๋“ฑ) ์ง€์› ๋“ฑ์ด ๋ฏธํกํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋ก์‹œ ๋ฏธ์‚ฌ์šฉ: ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ, Spring AOP์ฒ˜๋Ÿผ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•œ ์œ ์—ฐํ•œ ์œ„๋น™(Weaving)์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”ธ (2) AOP ์ž๋™ ๊ตฌํ˜„ (Spring AOP)

Spring Framework๋Š” AspectJ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€์˜ ํ†ตํ•ฉ์„ ํ†ตํ•ด ํ›จ์”ฌ ๊ฐ•๋ ฅํ•˜๊ณ  ํŽธ๋ฆฌํ•œ AOP ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋ณต์žกํ•œ Reflection ์ฝ”๋“œ ๋Œ€์‹ , ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ์„ค์ •์œผ๋กœ AOP๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Spring AOP๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ก์‹œ(Proxy) ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ ์‚ดํŽด๋ณด๊ธฐ:

  • MyMath.java: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง(๋ง์…ˆ, ๋บ„์…ˆ, ๊ณฑ์…ˆ)์„ ๊ฐ€์ง„ ํƒ€๊ฒŸ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. AOP ๊ด€๋ จ ์ฝ”๋“œ๊ฐ€ ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค. (@Component๋กœ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก)
  • LoggingAdvice.java: ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ(๋กœ๊ทธ ์ถœ๋ ฅ)์„ ๋‹ด๋‹นํ•˜๋Š” Aspect ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
    • @Aspect: ์ด ํด๋ž˜์Šค๊ฐ€ Aspect์ž„์„ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
    • @Component: Spring์ด ์ด Aspect๋ฅผ ๋นˆ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
    • @Around: Advice์˜ ์ข…๋ฅ˜๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. (ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„ ๋ฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋“ฑ ํฌ๊ด„์  ์ œ์–ด ๊ฐ€๋Šฅ)
    • "execution(* com.ABC.sbtch3.AOP.MyMath.add*(..))": Pointcut ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค. com.ABC.sbtch3.AOP ํŒจํ‚ค์ง€์˜ MyMath ํด๋ž˜์Šค์— ์žˆ๋Š” ์ด๋ฆ„์ด add๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ(๋ฆฌํ„ด ํƒ€์ž…(*), ํŒŒ๋ผ๋ฏธํ„ฐ(..) ๋ฌด๊ด€)๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ProceedingJoinPoint pjp: ํ˜„์žฌ Advice๊ฐ€ ์ ์šฉ๋œ Join Point(๋ฉ”์„œ๋“œ)์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์œผ๋ฉฐ, pjp.proceed()๋ฅผ ํ†ตํ•ด ์‹ค์ œ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Config.java: Spring ์„ค์ • ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
    • @EnableAspectJAutoProxy: ํ•ต์‹ฌ ์„ค์ •! ์ด ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ์–ด์•ผ Spring์ด @Aspect ๋นˆ์„ ์ฐพ์•„์„œ Pointcut์— ๋งค์นญ๋˜๋Š” ํƒ€๊ฒŸ ๊ฐ์ฒด์— ๋Œ€ํ•œ ํ”„๋ก์‹œ(Proxy) ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , Advice๋ฅผ ์ ์šฉ(Weaving)ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ์—†์œผ๋ฉด AOP๊ฐ€ ์ „ํ˜€ ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • @ComponentScan: @Component, @Aspect ๋“ฑ์ด ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์Šค์บ”ํ•˜์—ฌ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  • AopMain2.java: Spring ์ปจํ…์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , MyMath ๋นˆ์„ ๊ฐ€์ ธ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
Java
 
// Config.java (์ผ๋ถ€)
@EnableAspectJAutoProxy // <<-- ์ด๊ฒŒ ์žˆ์–ด์•ผ AOP๊ฐ€ ํ™œ์„ฑํ™”๋˜๊ณ  ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋จ!
@ComponentScan
@Configuration
class Config { }

// LoggingAdvice.java (์ผ๋ถ€)
@Component // Spring Bean์œผ๋กœ ๋“ฑ๋ก
@Aspect    // Aspect ํด๋ž˜์Šค์ž„์„ ์„ ์–ธ
class LoggingAdvice {
    // Around Advice + Pointcut ์„ค์ •
    @Around("execution(* com.ABC.sbtch3.AOP.MyMath.add*(..))")
    public Object methodClassLog(ProceedingJoinPoint pjp) throws Throwable {
        // ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ์‹œ์ž‘ ์ „ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ
        System.out.println("<<[start]" + pjp.getSignature().getName() + Arrays.toString(pjp.getArgs()));

        Object result = pjp.proceed(); // <<-- ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ(ํ•ต์‹ฌ ๋กœ์ง) ํ˜ธ์ถœ

        // ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ์ข…๋ฃŒ ํ›„ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ
        System.out.println("[end]>>" + ... + "ms");
        return result;
    }
}

// MyMath.java (์ผ๋ถ€) - ํƒ€๊ฒŸ ํด๋ž˜์Šค
@Component
class MyMath {
    int add(int a, int b) { /*...*/ }
    int add(int a, int b, int c) { /*...*/ }
    int multiply(int a, int b) { /*...*/ }
}

// AopMain2.java (์ผ๋ถ€)
ApplicationContext ac =  SpringApplication.run(Config.class);
MyMath mm = ac.getBean("myMath", MyMath.class); // <<-- ์‹ค์ œ๋กœ๋Š” MyMath์˜ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋จ
mm.add(3,5);        // -> LoggingAdvice ์ ์šฉ๋จ
mm.multiply(3,5);   // -> LoggingAdvice ์ ์šฉ ์•ˆ ๋จ (Pointcut ๋ถˆ์ผ์น˜)

์ฝ”๋“œ ๋ถ€์—ฐ ์„ค๋ช… ๋ฐ ์–ด๋…ธํ…Œ์ด์…˜ ์—ญํ• :

  • @EnableAspectJAutoProxy: Spring์—๊ฒŒ AspectJ ๊ธฐ๋ฐ˜์˜ AOP ์ฒ˜๋ฆฌ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ผ๊ณ  ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด ์–ด๋…ธํ…Œ์ด์…˜์ด ์—†์œผ๋ฉด Spring์€ @Aspect๊ฐ€ ๋ถ™์€ ๋นˆ์„ ๋ฐœ๊ฒฌํ•ด๋„ ๋ฌด์‹œํ•˜๊ณ  ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„ AOP๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • @Aspect: LoggingAdvice ํด๋ž˜์Šค๊ฐ€ ๋‹จ์ˆœํ•œ ๋นˆ์ด ์•„๋‹ˆ๋ผ, Advice์™€ Pointcut์„ ๋‹ด๊ณ  ์žˆ๋Š” ํŠน๋ณ„ํ•œ Aspect ๋ชจ๋“ˆ์ž„์„ Spring์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. @EnableAspectJAutoProxy๋Š” @Aspect๊ฐ€ ๋ถ™์€ ๋นˆ์„ ์ฐพ์•„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • @Around: ์—ฌ๋Ÿฌ Advice ํƒ€์ž… ์ค‘ ํ•˜๋‚˜๋กœ, ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „์ฒด๋ฅผ ๊ฐ์Œ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „, ํ›„, ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋“ฑ ๋ชจ๋“  ์‹œ์ ์— ๊ฐœ์ž…ํ•˜์—ฌ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๊ณ , ์‹ฌ์ง€์–ด ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ํ˜ธ์ถœ ์ž์ฒด๋ฅผ ๋ง‰์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. (pjp.proceed() ํ˜ธ์ถœ ์—ฌ๋ถ€)
  • execution(...) (Pointcut): Advice๋ฅผ ์–ด๋””์— ์ ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค. AspectJ Pointcut ํ‘œํ˜„์‹ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งค์šฐ ์ •๊ตํ•˜๊ฒŒ ์ ์šฉ ๋Œ€์ƒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์˜ˆ: ํŠน์ • ํŒจํ‚ค์ง€ ํ•˜์œ„, ํŠน์ • ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ, ํŠน์ • ์ด๋ฆ„ ํŒจํ„ด ๋“ฑ)
  • ProceedingJoinPoint pjp: @Around Advice ๋ฉ”์„œ๋“œ์˜ ํ•„์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ Advice๊ฐ€ ์ ์šฉ๋œ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ(Join Point)์— ๋Œ€ํ•œ ์ •๋ณด(๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜, ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ)๋ฅผ ์–ป๊ณ , pjp.proceed()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‹ค์ œ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ”„๋ก์‹œ(Proxy) ๋™์ž‘ ์›๋ฆฌ: @EnableAspectJAutoProxy๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด, Spring์€ Pointcut์— ๋งค์นญ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ๋นˆ(์—ฌ๊ธฐ์„œ๋Š” MyMath ๋นˆ)์„ ์ƒ์„ฑํ•  ๋•Œ, ์ง์ ‘ MyMath ๊ฐ์ฒด๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๋Œ€์‹  ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” MyMath์™€ ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค(๋˜๋Š” ์ƒ์† ๊ตฌ์กฐ)๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋‚ด๋ถ€์— ์‹ค์ œ MyMath ๊ฐ์ฒด(Target)๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ(AopMain2)๊ฐ€ ํ”„๋ก์‹œ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ(add())๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ํ”„๋ก์‹œ๋Š” ๋จผ์ € Aspect(LoggingAdvice)์˜ Advice๋ฅผ ์‹คํ–‰ํ•˜๊ณ , Advice ๋‚ด๋ถ€์—์„œ pjp.proceed()๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์‹ค์ œ MyMath ๊ฐ์ฒด์˜ add() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. multiply()์ฒ˜๋Ÿผ Pointcut์— ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ๋Š” Advice ์ ์šฉ ์—†์ด ๋ฐ”๋กœ ํƒ€๊ฒŸ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

โ€ป ๋น„๊ต ๋ถ„์„: ์ˆ˜๋™ AOP vs ์ž๋™ AOP

ํ•ญ๋ชฉ์ˆ˜๋™ AOP (Reflection)์ž๋™ AOP (Spring AOP + AspectJ)

 

๊ตฌํ˜„ ๋ณต์žก๋„ ๋†’์Œ (๋ฐ˜๋ณต์ ์ธ Reflection ์ฝ”๋“œ) ๋‚ฎ์Œ (์–ด๋…ธํ…Œ์ด์…˜, ์„ค์ • ๊ธฐ๋ฐ˜)
์„ฑ๋Šฅ ๋‚ฎ์Œ (Reflection ์˜ค๋ฒ„ํ—ค๋“œ) ์ƒ๋Œ€์ ์œผ๋กœ ์šฐ์ˆ˜ (ํ”„๋ก์‹œ ์˜ค๋ฒ„ํ—ค๋“œ, ์ตœ์ ํ™”)
๊ธฐ๋Šฅ/์œ ์—ฐ์„ฑ ์ œํ•œ์  (๊ธฐ๋ณธ์ ์ธ Around ํ‰๋‚ด) ๊ฐ•๋ ฅํ•จ (๋‹ค์–‘ํ•œ Advice, ์ •๊ตํ•œ Pointcut)
์ฝ”๋“œ ๊ฒฐํ•ฉ๋„ ๋†’์Œ (Advice ์ฝ”๋“œ๊ฐ€ ํƒ€๊ฒŸ ํ˜ธ์ถœ ๋กœ์ง๊ณผ ๊ฒฐํ•ฉ) ๋‚ฎ์Œ (Target ์ฝ”๋“œ๋Š” AOP ๋ชจ๋ฅด๊ฒŒ ์ž‘์„ฑ ๊ฐ€๋Šฅ)
  • ํ”„๋ ˆ์ž„์›Œํฌ ํ†ตํ•ฉ | ์–ด๋ ค์›€ | ์‰ฌ์›€ (Spring ์ปจํ…์ŠคํŠธ์™€ ์™„๋ฒฝ ํ†ตํ•ฉ) |
  • ํ”„๋ก์‹œ ์‚ฌ์šฉ | ์‚ฌ์šฉ ์•ˆ ํ•จ (์ง์ ‘ ํ˜ธ์ถœ ์ œ์–ด) | ์‚ฌ์šฉํ•จ (Dynamic Proxy ๋˜๋Š” CGLIB) |
  • ํ‘œ์ค€/๊ด€๋ก€ | ๋น„ํ‘œ์ค€์ , ํ•™์Šต์šฉ | Spring ํ‘œ์ค€, ์‹ค๋ฌด์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ |

๊ฒฐ๋ก 

AOP๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ์ฝ”๋“œ์˜ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด๋Š” ๊ฐ•๋ ฅํ•œ ํŒจ๋Ÿฌ๋‹ค์ž„์ž…๋‹ˆ๋‹ค. ์ˆ˜๋™ ๊ตฌํ˜„ ๋ฐฉ์‹(Reflection)์€ AOP์˜ ๊ธฐ๋ณธ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์—๋Š” ์„ฑ๋Šฅ, ๋ณต์žก์„ฑ, ๊ธฐ๋Šฅ ์ œํ•œ ๋“ฑ์˜ ํ•œ๊ณ„๊ฐ€ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, Spring AOP์™€ AspectJ๋ฅผ ํ™œ์šฉํ•œ ์ž๋™ ๊ตฌํ˜„ ๋ฐฉ์‹์€ @Aspect, @EnableAspectJAutoProxy ๋“ฑ์˜ ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ์„ค์ •์„ ํ†ตํ•ด ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜๋ฉฐ ํšจ์œจ์ ์œผ๋กœ AOP๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ํŠนํžˆ ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜์—ฌ ํƒ€๊ฒŸ ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ ์—†์ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ๋™์ ์œผ๋กœ ์œ„๋น™ํ•˜๋Š” ๋Šฅ๋ ฅ์€ Spring AOP์˜ ํ•ต์‹ฌ ์žฅ์ ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ˜„๋Œ€์ ์ธ Spring ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋‹น์—ฐํžˆ Spring AOP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊น…, ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ๋ณด์•ˆ ๋“ฑ ๋‹ค์–‘ํ•œ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ํ‘œ์ค€์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

 

 

 

๋ฐ˜์‘ํ˜•