AOP

강한친구·2022년 3월 30일
0

Spring 입문

목록 보기
10/10

Aspect Oriented Programming

언제 쓰는가

메소드가 1000개가 있다고해보자. 이 때, 누군가가 나타나서 이 메소드들의 호출시간을 알아오라고 시킨다고 하자.


public Long join(Member member) {
   	long start = System.currentTimeMillis();
     try {
       validateDuplicateMember(member); 
       memberRepository.save(member);
       return member.getId();
     } finally {
       long finish = System.currentTimeMillis();
       long timeMs = finish - start;
       System.out.println("join " + timeMs + "ms");
   }
 }

이런식으로 try finally 문을 이용해서 시작할 때 시간, 끝날 때 시간을 측정해서 값을 빼주는 방식을 떠올릴것이다.

근데 이러면 1000번을 다 해줘야하고 몇가지 문제점이 생긴다.

  1. 시간측정로직은 공통관심사항(Cross-cutting Concern)이지 핵심관심사항(Core Concern)이 아닌데 이 둘이 섞이게 되면서 코드 가독성도 떨어지고 유지보수도 힘들어진다.

    또한, 시간측정 로직을 별도의 로직으로 만들기도 어렵고, 앞서 언급한것처럼 메소드마다 다 해줘야한다.

    이런 상황을 해결하고자 나온것이 AOP이다.

AOP

package com.example.hellospring.aop;

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

@Aspect
public class TimeTraceAop {

    @Around("execution(* com.example.hellospring..*(..)) && !target(com.example.hellospring.SpringConfig)")
//    @Around("execution(* com.example.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");
        }
    }
}
    @Bean
    public TimeTraceAop timeTraceAop () {
        return new TimeTraceAop();
    }

AOP라는 패키지를 만들고, 그 안에 AOP를 구현해서 컨테이너에 올려주면 된다.

@Around

어라운드 어노테이션은 이 aop가 어디까지 적용되는지 지정해준다.

@Around("execution(* com.example.hellospring..*(..)) && !target(com.example.hellospring.SpringConfig)")
@Around("execution(* com.example.hellospring..*(..))")

문제는 2번째 방식으로 around를 적용하면 오류가 난다는점이다.

이 글을 참고하자.

결과물

보이는것처럼 시간이 잘 측정된다!

작동원리

AOP가 적용되는 부분에 관해서는 Bean을 Proxy Bean을 만든다. Spring은 시간을 측정하도록 코드가 조작된 Proxy를 호출하고, joinPoint를 통해 진짜 Bean을 호출하는 방식이다.

자세한 내용은 따로 정리하겠다.

0개의 댓글