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개의 댓글

관련 채용 정보