TIL no.100 - Spring - 2 - AOP

devzunky·2020년 3월 25일
0

Spring

목록 보기
2/2

Spring Triangle 중 하나인 AOP에 대해 알아보겠습니다.

AOP란 Aspect Oriented Programming의 약어로 번역하면 관점 지향 프로그래밍입니다.

흩어진 코드를 한 곳으로 모은다고 생각하면 쉽습니다.

1. AOP

코드를 먼저 보겠습니다.

class A {
    method a() {
        //do AAAA
        //do method a()
        //do BBBB
    }
    
    method b() {
        //do AAAA
        //do method b()
        //do BBBB
    }
    
    method c() {
        //do AAAA
        //do method c()
        //do BBBB
    }
}

A라는 클래스에는 a, b, c라는 메서드들이 있으며
각 메서드에는 공통적인 부분이 존재합니다.
AAAA와 BBBB에 해당하는 부분입니다.

그런데, 만약 이렇게 공통적인 부분을 변경해줘야 하는 일이 생긴다면
각 메서드의 코드들을 하나하나 고쳐줘야 합니다.

반복되는 코드들을 하나로 모아 관리하면 이런 불편함을 해결할 수 있습니다.

이를 AOP라고 합니다.

AOP를 할 수 있는 방법은 크게 3가지가 있습니다.
1. Compile
2. Byte Code 조작
3. Proxy Pattern

Compile

먼저, Compile을 이용하는 방법은
java 파일을 compile하면 class 파일이 생기게 되는데
java 코드에는 위의 반복 실행되는 코드를 넣지 않았지만
compile을 하고 생성된 class 파일에는 반복 실행되는 코드가 있는 것처럼 해주는 방법입니다.

이를 도식화 해보겠습니다.

A.java ----(AOP)----> A.class

Byte Code

두번째는 Byte Code를 조작하는 방법입니다.
java 파일을 컴파일 한 뒤,
class를 사용할 때 Runtime에서 class loader가 class를 읽습니다.
이렇게 class를 읽고 메모리에 Byte로 올릴 때
이 Byte를 조작하는 방법입니다.

class 파일에는 반복 실행되는 코드가 없습니다.
그런데 class를 loading하는 그 시점에서 메모리에서 반복실행되는 코드가 들어가는 것입니다.

A.java --------> A.class ----(AOP)----> Memory

위 두 방법은 AspectJ를 이용하는 방법입니다.

Proxy Pattern

마지막으로 Proxy Pattern이 있습니다.
Spring이 사용하는 방법입니다.

design pattern 중 하나를 이용해서 AOP와 같은 효과를 내는 것입니다.
Proxy Pattern에 대한 자세한 글은 이 글을 참조해주세요.

2. Spring AOP

Spring AOP는 annotaion을 이용합니다.

어떤 메서드를 실행하는데 얼마나 시간이 걸리는지 측정하고 싶은 경우
필요한 annotation을 만들어보겠습니다.

@Target(ElemetTyp.METHOD) //생성하는 annotaion을 어디에 사용할 것인지 Target을 지정합니다. 이 경우 Method에 붙이는 annotation이라는 것을 알립니다.
@Retention(RetentionPlicy.RUNTIME) //생성하는 annotation 정보를 언제까지 유지할 것인지 설정합니다. 이 경우 Runtime까지 유효한 annotation이라는 것을 알립니다.
public @interface LogExecutionTime {
}

현재 이 annotation은 주석과 같습니다.
이제 이 annotation이 기능을 가지도록 해보겠습니다.

@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();
        
        Object proceed = joinPoint.proceed();
        
        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());
        
        return proceed;
    }
}

이를 통해 @LogExecutionTime을 붙인 메서드의 경우 성능을 측정할 수 있습니다.

profile
devzunky@gmail.com

0개의 댓글