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

๐‘†๐‘ข๐‘›๐‘ โ„Ž๐‘–๐‘›๐‘’ ๐‘Ž๐‘“๐‘ก๐‘’๐‘Ÿ ๐‘Ÿ๐‘Ž๐‘–๐‘›โœง

[Spring] AOP ๋ณธ๋ฌธ

AOP (Aspect Oriented Programming) 

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

 

AOP์˜ ์žฅ์  ๋˜๋Š” ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

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

 

AOP ์ฃผ์š” ํ‚ค์›Œ๋“œ

  • Aspect
    • ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ(Crosscutting Concerns)๋ฅผ ๋ฌถ์–ด์„œ ๋ชจ๋“ˆํ™” ํ•œ ๊ฒƒ. ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ. Advice์™€ Point Cut์ด ๋“ค์–ด๊ฐ„๋‹ค.
  • Target
    • Aspect๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Advice๊ฐ€ ์ ์šฉ๋˜๋Š” ๋Œ€์ƒ(ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ๋“ฑ๋“ฑ)์„ ๋งํ•œ๋‹ค.
  •  Advice
    • ์–ด๋–ค ์ผ์„ ํ•ด์•ผ ํ•  ์ง€์— ๋Œ€ํ•œ ๊ฒƒ. ํ•ด์•ผ ํ•  ์ผ๋“ค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • Join Point
    • Around Advice์—์„œ ์‚ฌ์šฉํ•  ๊ณตํ†ต ๊ธฐ๋Šฅ ๋งค์„œ๋“œ๋Š” ๋Œ€๋ถ€๋ถ„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์€ ProceedingJoinPoint์˜ proceed() ๋งค์„œ๋“œ๋งŒ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค. ProceedingJoinPoint ์ธํ„ฐํŽ˜์ด์Šค์•ˆ์˜ proceed()๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋“œ๋ฐ”์ด์Šค ํ˜น์€ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  •  Point Cut
    • Join Point์˜ ์ƒ์„ธํ•œ ์ŠคํŽ™์„ ์ •์˜ํ•œ ๊ฒƒ. ์–ด๋””์— ์ ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. 
       @Pointcut("execution(์œ„์น˜)") = “ํ•ด๋‹น ์œ„์น˜์— ์žˆ๋Š” ๋ฉ”์„œ๋“œ์— aop๋ฅผ ์ ์šฉํ•œ๋‹ค”์™€ ๊ฐ™์€ ๊ตฌ์ฒด์ ์ธ ์ •๋ณด๋ฅผ ์ค€๋‹ค.

 

 

์ฃผ์š” Annotation

 

์ฃผ์š” ํ‚ค์›Œ๋“œ์™€ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ฐฐ์› ์œผ๋‹ˆ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด AOP๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜ˆ์ œ๋Š” ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์ธ๋ฐ์š”. ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ถœ๋ ฅํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด์„œ AOP ํŠน์ง•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

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

 

๋จผ์ € aop๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด์„œ๋Š” dependency๋ฅผ ์ถ”๊ฐ€๋ฅผ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. build.gradle ์— ๋ฐ‘์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  gradle ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด์„œ build ํ•ด์ค๋‹ˆ๋‹ค. ํ•ด๋‹น ์ž‘์—…์„ ์™„๋ฃŒํ•ด์•ผ @Aspect Annotation์ด ์ธ์‹์ด ๋ฉ๋‹ˆ๋‹ค.

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

 

์šฐ์„  aop๋ฅผ ์‚ฌ์šฉํ•˜์ง€์•Š๊ณ  ํ•ด๋‹น ์ž‘์—…์„ ๊ตฌํ˜„ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Custom annotation์„ ํ†ตํ•ด์„œ ํ•ด๋‹น annotation์ด ์„ค์ •๋œ ๋ฉ”์„œ๋“œ๋งŒ ์‹คํ–‰์‹œ๊ฐ„์„ ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก @Timer์„ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

@Timer

 

 

@Target ์€ Java compiler ๊ฐ€ annotation ์ด ์–ด๋””์— ์ ์šฉ๋ ์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์—์„œ ์‚ฌ์šฉํ•œ Timerํด๋ž˜์Šค ์œ„์— ์„ ์–ธํ•œ ElementType.TYPE, ElementType.METHOD์€ ํƒ€์ž… ์„ ์–ธ๊ณผ ๋ฉ”์„œ๋“œ ์„ ์–ธํ•  ๋•Œ ํ•ด๋‹น Annotation์„ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
@Retention ์€ ์–ด๋Š ์‹œ์ ๊นŒ์ง€ ์–ด๋…ธํ…Œ์ด์…˜์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ ธ๊ฐˆ์ง€ ์„ค์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. 
RetentionPolicy.RUNTIME์€ ๋Ÿฐํƒ€์ž„ ๋™์•ˆ์— ์œ ์ง€๋˜๊ณ , ๋Ÿฐํƒ€์ž„์„ ์ข…๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์‚ด์•„์žˆ๋‹ค๋Š” ๋ฉ”ํƒ€ ์ •๋ณด์ž…๋‹ˆ๋‹ค.

์ฃผ๋กœ custom annotation์„ ์„ค์ •ํ• ๋•Œ @Retention๊ณผ @Target annotation์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

 

 

๊ทธ๋‹ค์Œ, @GetMapping, @PostMapping, @DeleteMapping ์ปจํŠธ๋กค ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” RestApiController ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

RestApiController 

์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ์œ ํ‹ธ ์ค‘ ํ•˜๋‚˜์ธ StopWatch๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. aop๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๊ฐ ๋ฉ”์„œ๋“œ๋งˆ๋‹ค

StopWatch stopWatch = new StopWatch();
stopWatch.start();
stopWatch.stop();

์œ„์™€ ๊ฐ™์€ ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ์ค‘๋ณต์œผ๋กœ ์ ์–ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์ƒ๊ด€์—†๊ณ  ์‹ค์ œ ๋กœ์ง์ด ์•„๋‹Œ ๋ถ€๊ฐ€์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ๋ฐ˜๋ณต์ ์œผ๋กœ ๋“ค์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์„œ๋น„์Šค ๋กœ์ง์ธ ํ•ต์‹ฌ ์ฝ”๋“œ๋กœ๋งŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ถ€๊ฐ€์ ์ธ ์ฝ”๋“œ๋Š”  TimerAop ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋นผ์ฃผ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

TimerAop

 

Aop๋กœ ๋™์ž‘ํ•˜๊ธฐ์œ„ํ•ด @Aspect ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๊ณ  Spring์—์„œ ๊ด€๋ฆฌ๋  ์ˆ˜ ์žˆ๊ฒŒ @Component ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค.

@Pointcut ์—๋Š” aop๋ฅผ ์ ์šฉ์‹œํ‚ฌ path๋ฅผ ์ ์–ด์ค๋‹ˆ๋‹ค.  proceedingJoinPoint.proceed()๋Š”  aop๊ฐ€ ์ ์šฉ๋œ ๋ฉ”์†Œ๋“œ ์ „์ฒด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์ƒ์œ„ ํด๋ž˜์Šค์ธ Object ํƒ€์ž…์œผ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค.

์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ธฐ์œ„ํ•ด์„œ ์ „ํ›„ ์‹œ๊ฐ„์ด ํ•„์š”ํ•œ๋ฐ @before, @After์€ ์‹œ๊ฐ„์„ ๊ณต์œ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— @Around annotaion์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.  @Around ์–ด๋…ธํ…Œ์ด์…˜์€ ๋Œ€์ƒ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „, ํ›„ ์‹œ์ ์— ๊ณตํ†ต๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ๋งค์„œ๋“œ, cut() ๋ฉ”์„œ๋“œ์™€ enableTImer() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ์–ดํ•œ๋‹ค๊ณ  ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, @Around ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด cut(), enableTimer()์—์„œ ์„ค์ •ํ•œ aop ์ ์šฉ ์œ„์น˜์˜ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„๋กœ around() ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ ๊ธฐ๋ก์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. 

 

RestApiController 

aop๋ฅผ ๊ตฌํ˜„ํ•œํ›„ RestApiController ํด๋ž˜์Šค์—๋Š” ์„œ๋น„์Šค ๋กœ์ง๋งŒ ๋‚จ์•„ ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ  ๊น”๋”ํ•ด์ง„ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์‹์œผ๋กœ aop๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ํ•ต์‹ฌ ๋กœ์ง์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.