๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

[Spring] ์Šคํ”„๋ง AOP ๊ฐœ๋… ์ดํ•ด ๋ฐ ์ ์šฉ ๋ฐฉ๋ฒ•

by Leica 2020. 2. 29.
๋ฐ˜์‘ํ˜•

[Spring] ์Šคํ”„๋ง AOP ๊ฐœ๋… ์ดํ•ด ๋ฐ ์ ์šฉ ๋ฐฉ๋ฒ•

1. AOP(Aspect Oriented Programming)

Spring์€ Spring Triangle์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ์„ธ ๊ฐ€์ง€ ๊ฐœ๋…์„ ์ œ๊ณตํ•ด์ค€๋‹ค. ๊ฐ๊ฐ IoC, AOP, PSA๋ฅผ ์ผ์ปซ๋Š”๋‹ค.

AOP๋Š” Aspect Oriented Programming์˜ ์•ฝ์ž๋กœ '์ธก๋ฉด/์–‘์ƒ ์ง€ํ–ฅ์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ'์ด๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

 

'์ธก๋ฉด/์–‘์ƒ ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ'์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”๊ฐ€?

 

class A {
 
    method a() {
        AAAA
 
        method a๊ฐ€ ํ•˜๋Š” ์ผ๋“ค
 
        BBBB
    }
 
    method b() {
        AAAA
 
        method b๊ฐ€ ํ•˜๋Š” ์ผ๋“ค
 
        BBBB
    }
}
 
class B {
    method c() {
        AAAA
 
        method c๊ฐ€ ํ•˜๋Š” ์ผ๋“ค
 
        BBBB
    }
}
cs

์œ„์™€ ๊ฐ™์ด ๋™์ผํ•œ ์ผ์„ ํ•˜๋Š” ์ฝ”๋“œ AAAA, BBBB๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ์„œ ์‚ฌ์šฉ๋˜๊ณ  ์ด๋ ‡๊ฒŒ ํฉ์–ด์ ธ์žˆ์œผ๋ฉด ์ฝ”๋“œ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ผ์ผ์ด ๋‹ค ์ฐพ์•„์„œ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค.

AOP๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๊ณ  ์—ฌ๋Ÿฌ๊ตฐ๋ฐ์„œ ์‚ฌ์šฉ๋˜๋Š” ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋–ผ์–ด๋‚ด์„œ ๋ถ„๋ฆฌํ•˜๊ณ , method a, b, c๋Š” ์ž์‹ ์ด ํ•ด์•ผํ•  ์ž‘์—…๋งŒ ๊ฐ–๊ณ ์žˆ์ž๋Š” ๊ฐœ๋…์ด๋‹ค.

์—ฌ๊ธฐ์„œ '์—ฌ๋Ÿฌ๊ตฐ๋ฐ์„œ ์‚ฌ์šฉ๋˜๋Š” ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ'๊ฐ€ AOP์—์„œ ๋งํ•˜๋Š” 'aspect'๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.

 

2. ํ”„๋ก์‹œ ํŒจํ„ด

Spring AOP๋Š” ํ”„๋ก์‹œ ํŒจํ„ด์ด๋ผ๋Š” ๋””์ž์ธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์„œ AOP ํšจ๊ณผ๋ฅผ ๋‚ธ๋‹ค.

ํ”„๋ก์‹œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค ํ• ๋•Œ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ• ์ˆ˜ ์žˆ๋‹ค.

 

์–ด๋–ค ํด๋ž˜์Šค๊ฐ€ Spring AOP์˜ ๋Œ€์ƒ์ด๋ผ๋ฉด ๊ทธ ๊ธฐ์กด ํด๋ž˜์Šค์˜ ๋นˆ์ด ๋งŒ๋“ค์–ด์งˆ๋•Œ Spring AOP๊ฐ€ ํ”„๋ก์‹œ(๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ ํด๋ž˜์Šค)๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค๊ณ  ์›๋ณธ ํด๋ž˜์Šค ๋Œ€์‹  ํ”„๋ก์‹œ๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  ์›๋ณธ ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์ง€์ ์—์„œ ํ”„๋ก์‹œ๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•œ๋‹ค.

 

Spring์˜ PetClinic ์˜ˆ์ œ์—์„œ OwnerRepository ์ธํ„ฐํŽ˜์ด์Šค์˜ @Transactional ์• ๋…ธํ…Œ์ด์…˜์ด ์ด์— ํ•ด๋‹นํ•œ๋‹ค.

 

@Transactional ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด์žˆ์œผ๋ฉด OwnerRepository ํƒ€์ž…์˜ ํ”„๋ก์‹œ๊ฐ€ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง€๊ณ  Spring AOP์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” OwnerRepository์˜ ํ”„๋ก์‹œ์—๋Š” @Transactional ์• ๋…ธํ…Œ์ด์…˜์ด ์ง€์‹œํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์‚ฝ์ž…๋œ๋‹ค.

 

@Transactional ์• ๋…ธํ…Œ์ด์…˜์— ์˜ํ•ด ์ถ”๊ฐ€๋˜๋Š” ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

JDBC์—์„œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๋ฉด SQL ์‹คํ–‰๋ฌธ ์•ž๋’ค์— setAutoCommit()์™€ commit()/rollback() ์ฝ”๋“œ๊ฐ€ ํ•ญ์ƒ ๋ถ™๋Š”๋ฐ @Transactional ์• ๋…ธํ…Œ์ด์…˜์€ ํ”„๋ก์‹œ์— ์ž๋™์œผ๋กœ ๊ทธ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์„œ ๋ฐ˜๋ณต, ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๊ฒŒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์ด๋กœ ์ธํ•ด ๊ฐœ๋ฐœ์ž๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

3. Spring AOP ์ ์šฉ ์˜ˆ์ œ

Spring์ด ์ œ๊ณตํ•˜๋Š” ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ AOP๋ฅผ ์ง์ ‘ ์ ์šฉํ•ด๋ณด์ž.

Spring PetClinic ์˜ˆ์ œ์˜ OwnerController์˜ ๋ฉ”์†Œ๋“œ๋“ค์— ๋ฉ”์†Œ๋“œ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค.

 

- [Spring] ์Šคํ”„๋ง ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ PetClinic ๋นŒ๋“œ ๋ฐ ์‹คํ–‰ํ•˜๊ธฐ

 

์šฐ์„  ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์— @LogExecutionTime ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ธ๋‹ค.

 

@LogExecutionTime์€ ์ œ๊ณต๋˜๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด ์•„๋‹Œ ์ƒˆ๋กœ ์ •์˜ํ•ด์•ผํ•˜๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด๋ฏ€๋กœ ์ง€๊ธˆ์€ ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

Alt + Enter๋ฅผ ๋ˆŒ๋Ÿฌ quick fixes๋ฅผ ๋„์šฐ๊ณ  Create annotation 'LogExecutionTime'์„ ํด๋ฆญํ•œ๋‹ค.

 

OK๋ฅผ ํด๋ฆญํ•œ๋‹ค.

 

๋นˆ ์• ๋…ธํ…Œ์ด์…˜์ด ๋งŒ๋“ค์–ด์กŒ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์• ๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•˜๊ณ  ๋ช‡๊ฐ€์ง€ ์„ค์ •์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
package org.springframework.samples.petclinic.owner;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
cs

 

@Target(ElementType.METHOD)

์• ๋…ธํ…Œ์ด์…˜์„ ๋ฉ”์†Œ๋“œ์— ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๊ณ  ์„ค์ •ํ•œ๋‹ค.

 

@Retention(RetentionPolicy.RUNTIME)

์• ๋…ธํ…Œ์ด์…˜์ด RUNTIME๊นŒ์ง€ ์œ ์ง€๋˜๋„๋ก ์„ค์ •ํ•œ๋‹ค.

 

์–ด๋–ค ๋ฉ”์†Œ๋“œ์— AOP๋ฅผ ์ ์šฉํ• ๊ฑด์ง€ ์•Œ๋ ค์ฃผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•˜์˜€๋‹ค.

์ด์ œ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์— ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์‹ค์ œ aspect๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

 

๊ฐ™์€ ํŒจํ‚ค์ง€์— LogAspect ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.springframework.samples.petclinic.owner;
 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
 
@Component
@Aspect
public class LogAspect {
    
    Logger logger = LoggerFactory.getLogger(LogAspect.class);
    
    @Around("@annotation(LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        // @LogExecutionTime ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด์žˆ๋Š” ํƒ€๊ฒŸ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰
        Object proceed = joinPoint.proceed();
        
        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());
        
        return proceed; // ๊ฒฐ๊ณผ ๋ฆฌํ„ด
    }
}
cs

 

Logger logger = LoggerFactory.getLogger(LogAspect.class);

slf4j๋กœ ๋กœ๊ฑฐ๋ฅผ ๋งŒ๋“ ๋‹ค.

 

@Around("@annotation(LogExecutionTime)")

์ด ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ธ ๋ฉ”์†Œ๋“œ์—์„œ๋Š” ProceedingJoinPoint ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

์• ๋…ธํ…Œ์ด์…˜์˜ value๋ฅผ "@annotation(LogExecutionTime)"๋กœ ์ง€์ •ํ•จ์œผ๋กœ์„œ

joinPoint๋Š” @LogExecutionTime๋ฅผ ๋ถ™์ธ ํƒ€๊ฒŸ ๋ฉ”์†Œ๋“œ๋ฅผ ์˜๋ฏธํ•˜๊ฒŒ ๋œ๋‹ค.

 

Object proceed = joinPoint.proceed();

ํƒ€๊ฒŸ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

์ด ๋ผ์ธ ์•ž ๋’ค๋กœ StopWatch๋ฅผ ์ด์šฉํ•œ ๋ฉ”์†Œ๋“œ ์„ฑ๋Šฅ ์ธก์ • ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.


์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

 

StopWatch๋ฅผ ์‚ฌ์šฉํ•œ ๋ฉ”์†Œ๋“œ ์„ฑ๋Šฅ ์ธก์ • ๊ฒฐ๊ณผ

์œ„์™€ ๊ฐ™์ด OwnerController์˜ ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์‹œ LogAspect์— ์ถ”๊ฐ€ํ•œ ๋ฉ”์†Œ๋“œ ์„ฑ๋Šฅ ์ธก์ • ๊ฒฐ๊ณผ๊ฐ€ ์ฝ˜์†”์— ์ถœ๋ ฅ๋œ๋‹ค.

 

์ด๊ฒƒ์ด aspect์ด๋ฉฐ Spring์ด ์ œ๊ณตํ•ด์ฃผ๋Š” ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ AOP์ด๋‹ค.

์ด๋ ‡๊ฒŒ ์ ์šฉํ•œ AOP๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ”„๋ก์‹œ ํŒจํ„ด ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

OwnerController(ํƒ€๊ฒŸ)์—๋Š” ์• ๋…ธํ…Œ์ด์…˜ ์™ธ์—๋Š” ์•„๋ฌด๋Ÿฐ ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์ง€ ์•Š์•˜๋‹ค.

 

References

์ธํ”„๋Ÿฐ - ๋ฐฑ๊ธฐ์„ ๋‹˜์˜ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ์ž…๋ฌธ(๊ฐœ์ •ํŒ)

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€