intro

์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ ์„ ๋“ฃ๊ณ  ๋‚˜์„œ ๊ฐœ์ธ์ ์œผ๋กœ AOP์— ๋Œ€ํ•ด ์ถ”๊ฐ€๋กœ ์ •๋ฆฌํ•ด ๋ณด์•˜๋‹ค.
ํ•ด๋‹น ๊ฐ•์˜์— ๋‚˜์˜จ ์ฝ”๋“œ ๋ถ„์„ ์™ธ์—๋„ ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ๋„ ์‚ดํŽด๋ณด์•˜๋‹ค.

AOP (Aspect Oriented Programming)๋ž€?

AOP๋Š” Aspect Oriented Programming์˜ ์•ฝ์ž๋กœ ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ผ๊ณ  ๋ถˆ๋ฆฐ๋‹ค. ๊ด€์  ์ง€ํ–ฅ์€ ์–ด๋–ค ๋กœ์ง์„ ๊ธฐ์ค€์œผ๋กœ ํ•ต์‹ฌ์ ์ธ ๊ด€์ , ๋ถ€๊ฐ€์ ์ธ ๊ด€์ ์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ๋ณด๊ณ  ๊ทธ ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋ชจ๋“ˆํ™” ํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

  • ๋ชจ๋“ˆํ™” : ์–ด๋–ค ๊ณตํ†ต๋œ ๋กœ์ง์ด๋‚˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ๋ฌถ๋Š” ๊ฒƒ

์˜ˆ๋ฅผ ๋“ค์–ด ํ•ต์‹ฌ์ ์ธ ๊ด€์ ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋  ์ˆ˜ ์žˆ๊ณ , ๋ถ€๊ฐ€์ ์ธ ๊ด€์ ์€ ํ•ต์‹ฌ ๋กœ์ง์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ–‰ํ•ด์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ, ๋กœ๊น…, ํŒŒ์ผ ์ž…์ถœ๋ ฅ ๋“ฑ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

AOP๋Š” ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ(Crosscutting Concerns)๋ฅผ ๋ชจ๋“ˆํ™” ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•์ด๋‹ค

[๊ทธ๋ฆผ 1] AOP ์˜ˆ์‹œ

[๊ทธ๋ฆผ 1]๊ณผ ๊ฐ™์ด ํด๋ž˜์Šค A, B, C์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ์ƒ‰๊น” ๋ธ”๋ก์€ ์ค‘๋ณต๋˜๋Š” ๋ฉ”์„œ๋“œ, ํ•„๋“œ, ์ฝ”๋“œ ๋“ฑ์ด๋‹ค. ์ด๋•Œ ์˜ˆ๋ฅผ ๋“ค์–ด ํด๋ž˜์Šค A์˜ ์ฃผํ™ฉ์ƒ‰ ๋ธ”๋ก ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ํด๋ž˜์Šค B, C์˜ ์ฃผํ™ฉ์ƒ‰ ๋ถ€๋ถ„๋„ ์ผ์ผ์ด ์ฐพ์•„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” SOLID์›์น™์„ ์œ„๋ฐฐํ•˜๋ฉฐ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ ์†Œ์Šค ์ฝ”๋“œ์ƒ์—์„œ ๊ณ„์† ๋ฐ˜๋ณตํ•ด์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ถ€๋ถ„๋“ค์„ **ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ(Crosscutting Concerns)**๋ผ๊ณ  ํ•œ๋‹ค.

๊ฒฐ๊ตญ AOP์—์„œ ๊ฐ ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋กœ์ง์„ ๋ชจ๋“ˆํ™”ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ชจ๋“ˆํ™”ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ๋‹ค. [๊ทธ๋ฆผ 1]๊ณผ ๊ฐ™์ด ์ฃผํ™ฉ์ƒ‰, ํŒŒ๋ž€์ƒ‰, ๋นจ๊ฐ„์ƒ‰ ๋ธ”๋ก์ฒ˜๋Ÿผ ๋ชจ๋“ˆํ™” ์‹œ์ผœ๋†“๊ณ  ์–ด๋””์— ์ ์šฉ์‹œํ‚ฌ์ง€๋งŒ ์ •์˜ํ•ด์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋•Œ ๋ชจ๋“ˆํ™” ์‹œ์ผœ๋†“์€ ๋ธ”๋Ÿญ์„ Aspect๋ผ๊ณ  ํ•œ๋‹ค.

 

๊ณตํ†ต ๊ด€์‹ฌ ์‚ฌํ•ญ(cross-cutting concern) vs ํ•ต์‹ฌ ๊ด€์‹ฌ ์‚ฌํ•ญ(core concern) ๋ถ„๋ฆฌ

AOP ๊ด€๋ จ ์šฉ์–ด

  • Aspect : ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ชจ๋“ˆํ™” ํ•œ ๊ฒƒ.
  • Target : Aspect๋ฅผ ์ ์šฉํ•˜๋Š” ๊ณณ. ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ๋“ฑ..
  • Advice : ์‹ค์งˆ์ ์œผ๋กœ ์–ด๋–ค ์ผ์„ ํ•ด์•ผ ํ•  ์ง€์— ๋Œ€ํ•œ ๊ฒƒ, ์‹ค์งˆ์ ์ธ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋‹ด์€ ๊ตฌํ˜„์ฒด
  • Join Point : Advice๊ฐ€ ์ ์šฉ๋  ์œ„์น˜ ํ˜น์€ ๋ผ์–ด๋“ค ์ˆ˜ ์žˆ๋Š” ์‹œ์ . ๋ฉ”์„œ๋“œ ์ง„์ž… ์‹œ์ , ์ƒ์„ฑ์ž ํ˜ธ์ค„ ์‹œ์ , ํ•„๋“œ์—์„œ ๊บผ๋‚ด์˜ฌ ์‹œ์  ๋“ฑ ๋ผ์–ด๋“ค ์‹œ์ ์„ ์˜๋ฏธ. ์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง์—์„œ Join Point๋Š” ์–ธ์ œ๋‚˜ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์‹œ์ ์„ ์˜๋ฏธ ํ•œ๋‹ค.
  • Point Cut : Join Point์˜ ์ƒ์„ธํ•œ ์ŠคํŽ™์„ ์ •์˜ํ•œ ๊ฒƒ. "A๋ž€ ๋ฉ”์„œ๋“œ์˜ ์ง„์ž… ์‹œ์ ์— ํ˜ธ์ถœํ•  ๊ฒƒ"์ฒ˜๋Ÿผ ๊ตฌ์ฒด์ ์œผ๋กœ Advice๊ฐ€ ์‹คํ–‰๋  ์‹œ์ ์„ ์ •ํ•จ.

AOP ์ ์šฉ ๋ฐฉ๋ฒ•

  1. ์ปดํŒŒ์ผ ํƒ€์ž„ ์ ์šฉ
  • ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ AOP๊ฐ€ ์ ์šฉ๋œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•.
  1. ๋กœ๋“œ ํƒ€์ž„ ์ ์šฉ
  • ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์ปดํŒŒ์ผํ•œ ๋’ค, ํด๋ž˜์Šค๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ์‹œ์ ์— ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•
  1. ๋Ÿฐํƒ€์ž„ ์ ์šฉ
  • ์Šคํ”„๋ง AOP๊ฐ€ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•. A๋ผ๋Š” ํด๋ž˜์Šค ํƒ€์ž…์˜ Bean์„ ๋งŒ๋“ค ๋•Œ A ํƒ€์ž…์˜ Proxy Bean์„ ๋งŒ๋“ค์–ด Proxy Bean์ด Aspect ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•.

์Šคํ”„๋ง AOP

  • ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” ์Šคํ”„๋ง AOP๋Š” ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์˜ AOP ๊ตฌํ˜„์ฒด์ด๋‹ค.
  • ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ ‘๊ทผ ์ œ์–ด ๋ฐ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค.
  • ์Šคํ”„๋ง AOP๋Š” ์Šคํ”„๋ง Bean์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ชจ๋“  AOP ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด ์•„๋‹Œ, ์ค‘๋ณต ์ฝ”๋“œ, ํ”„๋ก์‹œ ํด๋ž˜์Šค ์ž‘์„ฑ์˜ ๋ฒˆ๊ฑฐ๋กœ์›€ ๋“ฑ ํ”ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด๋‹ค.
  • ์Šคํ”„๋ง AOP๋Š” ์ˆœ์ˆ˜ ์ž๋ฐ”๋กœ ๊ตฌํ˜„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠน๋ณ„ํ•œ ์ปดํŒŒ์ผ ๊ณผ์ •์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.
  • ํ”„๋ก์‹œ ํŒจํ„ด

[๊ทธ๋ฆผ 2] Proxy ํŒจํ„ด

ํ”„๋ก์‹œ ํŒจํ„ด์—์„œ๋Š” interface๊ฐ€ ์กด์žฌํ•˜๊ณ  Client๋Š” ์ด interface ํƒ€์ž…์œผ๋กœ Proxy ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Proxy ๊ฐ์ฒด๋Š” ๊ธฐ์กด์˜ ํƒ€๊ฒŸ ๊ฐ์ฒด(Real Subject)๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. Proxy ๊ฐ์ฒด์™€ ๊ธฐ์กด์˜ ํƒ€๊ฒŸ ๊ฐ์ฒด์˜ ํƒ€์ž…์€ ๊ฐ™๊ณ , Proxy๋Š” ์›๋ž˜ ํ•  ์ผ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Real Subject๋ฅผ ๊ฐ์‹ธ์„œ Client์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์Šคํ”„๋ง AOP ๊ตฌํ˜„

maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

gradle

implementation 'org.springframework.boot:spring-boot-starter-aop'

์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ, ์›น MVC, DB ์ ‘๊ทผ ๊ธฐ์ˆ ์— ๋‚˜์˜จ ์ฝ”๋“œ๋กœ AOP๋ฅผ ๋จผ์ € ๋ถ„์„ํ•ด๋ณธ๋‹ค.

1. ์‹œ๊ฐ„ ์ธก์ • AOP ๋“ฑ๋ก

package hello.hellospring.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

// AOP ์ ์šฉ, ์Šคํ”„๋ง ๋นˆ ๋“ฑ๋ก
@Aspect
@Component
public class TimeTraceAop {
    // ๊ณตํ†ต๊ด€์‹ฌ์‚ฌํ•ญ์„ ์ ์šฉํ•  ๊ณณ(hello.hellospring ํŒจํ‚ค์ง€ ํ•˜์œ„ ๋ชจ๋‘) ํƒ€๊ฒŸํŒ…
    @Around("execution(* hello.hellospring..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();    // ์‹œ์ž‘ ์‹œ๊ฐ

        System.out.println("START: " + joinPoint.toString());

        try {
            return joinPoint.proceed();
        } finally {
            long finish = System.currentTimeMillis();   // ์ข…๋ฃŒ ์‹œ๊ฐ
            long timeMs = finish - start;   // ํ˜ธ์ถœ ์‹œ๊ฐ„

            System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
        }
    }
}

์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋ฐฉ์‹๊ณผ SpringConfig์— ์ง์ ‘ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๋ฐฉ์‹ 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํ•œ๊ฒŒ ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋ฐฉ์‹์ธ @Component ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ TimeTraceAop ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๊ณตํ†ต ๊ด€์‹ฌ ์‚ฌํ•ญ์ด๊ธฐ ๋•Œ๋ฌธ์— SpringConfig ํŒŒ์ผ์— ์ง์ ‘ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ธํ„ฐ์…‰ํŠธ๊ฐ€ ๊ฑธ๋ ค์„œ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์ž„

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

1) localhost:8080 ์‹คํ–‰

https://blog.kakaocdn.net/dn/eDCnta/btrA2BkeBnK/FJ7Dwnkw6bKXTeMg7rCKe1/img.png

2) ํšŒ์› ๋ชฉ๋ก ํด๋ฆญ

https://blog.kakaocdn.net/dn/c7x5vo/btrAR6Tafva/qIOOXHEOg7dwOJr3opTwNk/img.png

3) ํšŒ์› ๊ฐ€์ž… ํด๋ฆญ

https://blog.kakaocdn.net/dn/rGsZp/btrA0y9mT7j/nLbk8iwKYNQvD8tZbiLotK/img.png

4) id ์ž…๋ ฅ ํ›„ ๋“ฑ๋ก

https://blog.kakaocdn.net/dn/zfehN/btrA3sUVk4d/6xymJDbQKCYa1UoFhkQwxk/img.png

3. ํ•ด๊ฒฐ

  • ํšŒ์›๊ฐ€์ž…, ํšŒ์› ์กฐํšŒ๋“ฑ ํ•ต์‹ฌ ๊ด€์‹ฌ์‚ฌํ•ญ๊ณผ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๊ณตํ†ต ๊ด€์‹ฌ ์‚ฌํ•ญ์„ ๋ถ„๋ฆฌํ•œ๋‹ค.
  • ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๋กœ์ง์„ ๋ณ„๋„์˜ ๊ณตํ†ต ๋กœ์ง์œผ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.
  • ํ•ต์‹ฌ ๊ด€์‹ฌ ์‚ฌํ•ญ์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฉด ์ด ๋กœ์ง๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋œ๋‹ค.
  • ์›ํ•˜๋Š” ์ ์šฉ ๋Œ€์ƒ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.(ํƒ€๊ฒŸํŒ…)

2. ์Šคํ”„๋ง์˜ AOP ๋™์ž‘ ๋ฐฉ์‹ ์„ค๋ช…

AOP๋Š” Proxy๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค!

1. AOP ์ ์šฉ ์ „ ์˜์กด๊ด€๊ณ„

https://blog.kakaocdn.net/dn/uDphv/btrA0zHgFqx/540w6JRrlDK6ZpOCK7KHb1/img.png

2. AOP ์ ์šฉ ํ›„ ์˜์กด๊ด€๊ณ„

https://blog.kakaocdn.net/dn/bkWYIa/btrAR7R6Vkc/5Fhffdb5nmW4QSAqeKytXK/img.png

1) AOP๋ฅผ ์ ์šฉํ•˜๋ฉด Proxy(๊ฐ€์งœ memberService)๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.

2) ์‹ค์ œ๋กœ๋Š” memberController๊ฐ€ memberService๋ผ๋Š” Proxy(๊ฐ€์งœ memberService)๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

3) joinPoint.proceed()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์‹ค์ œ memberService๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

<Proxy ์ฃผ์ž… ์ฝ˜์†”์—์„œ ์ถœ๋ ฅํ•ด์„œ ํ™•์ธํ•˜๊ธฐ>

@Controller
public class MemberController {
    // private final MemberService memberService = new MemberService();
    // ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก์„ ํ•ด๋‘๊ณ  ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๋ฐฉ์‹(๊ฐ™์€ MemberService๋ฅผ ๊ณต์œ ํ•˜๋„๋ก)
    private final MemberService memberService;

    // ํšŒ์› ์ปจํŠธ๋กค๋Ÿฌ & ํšŒ์› ์„œ๋น„์Šค ์—ฐ๊ฒฐ
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
        // memberController๊ฐ€ Proxy(๊ฐ€์งœ memberService)๋ฅผ ํ˜ธ์ถœํ•จ์„ ํ™•์ธ
        System.out.println("memberService = " + memberService.getClass());
        ...
    }

์•„๋ž˜์™€ ๊ฐ™์ด ์‹ค์ œ MemberService๊ฐ€ ์•„๋‹Œ ๋’ค์— ๋ฌด์—‡์ธ๊ฐ€ ๋ถ™์€ Proxy๊ฐ€ ์ฃผ์ž…๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

https://blog.kakaocdn.net/dn/xmUNz/btrA32V1DAL/udtgyF4ksv4S4vAiXmGplK/img.png

3. AOP ์ ์šฉ ์ „ ์ „์ฒด ๊ทธ๋ฆผ

https://blog.kakaocdn.net/dn/9xuB4/btrA0WBI5JC/R0Z2uIPLFGCGvshkZkRIv1/img.png

4. AOP ์ ์šฉ ํ›„ ์ „์ฒด ๊ทธ๋ฆผ

https://blog.kakaocdn.net/dn/CK9UE/btrA34GjI0D/sjYyHOr0xaIt6aMROjiCW0/img.png

Spring AOP๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์œ„์™€ ๊ฐ™์ด ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์ด์ œ ๋‹ค๋ฅธ ์ฝ”๋“œ๋กœ AOP๋ฅผ ๋ถ„์„ํ•ด ๋ณธ๋‹ค.

์ง€๊ธˆ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ์€ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•ด์ฃผ๋Š” ๋กœ์ง์ด๋‹ค.

@Component
@Aspect
public class PerfAspect {

    @Around("execution(* com.example..*.EventService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object reVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return reVal;
    }
}

์Šคํ”„๋ง AOP๋Š” Bean์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค๊ณ  ํ–ˆ๋‹ค. ๋”ฐ๋ผ์„œ @Component ์–ด๋…ธํ…Œ์ด์…˜ ๋“ฑ์„ ํ†ตํ•ด ์Šคํ”„๋ง Bean์œผ๋กœ ๋“ฑ๋กํ•ด์ค€ ๋’ค ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. @Aspect ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Aspect๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ด์ค€๋‹ค.

logPerf() ๋ฉ”์„œ๋“œ๋Š” @Around ์–ด๋…ธํ…Œ์ด์…˜์˜ execution์„ ํ†ตํ•ด Advice๋ฅผ ์ ์šฉํ•  ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์˜ˆ์‹œ๋กœ ๋“ค์ž๋ฉด com.example ๋ฐ‘์˜ ๋ชจ๋“  ํด๋ž˜์Šค์— ์ ์šฉํ•˜๊ณ , EventService ๋ฐ‘์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ์ ์šฉํ•˜๋ผ๋Š” ๋œป์ด๋‹ค.

์œ„์™€ ๊ฐ™์€ ๊ฒฝ๋กœ ์ง€์ • ๋ฐฉ์‹์ด ์•„๋‹Œ ํŠน์ • ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํฌ์ธํŠธ์— ํ•ด๋‹น Aspect๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

@Component
@Aspect
public class PerfAspect {

  @Around("@annotation(PerfLogging)")
  public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed();
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}

์œ„์™€ ๊ฐ™์ด @Around ์–ด๋…ธํ…Œ์ด์…˜์— @annotation(PerfLogging)์ฒ˜๋Ÿผ ์ ์šฉ๋  ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿผ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์ ์šฉ์‹œํ‚ฌ ํŠน์ • ๋ฉ”์„œ๋“œ์— @PerfLogging ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด logPerf() ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•œ๋‹ค.

ํ˜น์€ ํŠน์ • Bean ์ „์ฒด์— ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์ ์šฉ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

// Aspect ์ •์˜@Component
@Aspect
public class PerfAspect {

// ๋นˆ์ด ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๋ชจ๋“  ํผ๋ธ”๋ฆญ ๋ฉ”์˜๋“œ@Around("bean(simpleServiceEvent)")
  public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed();
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}

์œ„์™€ ๊ฐ™์ด @Around ์–ด๋…ธํ…Œ์ด์…˜์— bean(simpleServcieEvent)์ฒ˜๋Ÿผ ์ ์šฉ๋  ๋นˆ์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿผ ํ•ด๋‹น ๋นˆ์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ชจ๋“  public ๋ฉ”์„œ๋“œ์— ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ์ ์šฉ๋œ๋‹ค.

@Around ์™ธ์— ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ์˜ Aspect ์‹คํ–‰ ์‹œ์ ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ๋“ค์ด ์žˆ๋‹ค.

  • @Before : Advice ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— Advice ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
  • @After : ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ์— ๊ด€๊ณ„์—†์ด ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๊ณผ ์™„๋ฃŒ๋˜๋ฉด Advice ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
  • @AfterRunning : ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•œ ํ›„์— Advice ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
  • @AfterThrowing : ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๊ฐ€ ์ˆ˜ํ–‰ ์ค‘ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋ฉด Advice ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
  • @Around : Advice๊ฐ€ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ์‹ธ ํƒ€๊ฒŸ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „, ํ›„์— Advice ๊ธฐ๋Šฅ ์ˆ˜ํ–‰