[스프링 입문] Section 7. AOP

 

본 포스팅의 내용은

인프런 김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의 기반으로 작성했습니다.

 
 

🌱 AOP가 필요한 상황

예를 들어, 모든 메서드의 호출 시간을 측정하고 싶다면?

어느 날 직장 상사가 어플리케이션의 모든 메서드 호출 시간(초)을 측정하라고 지시했다.

밤을 새며 아래와 같이 모든 메서드에 하나하나 시간 측정하는 로직을 추가했다.

 

public class MemberService {
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    /**
     * 회원 가입
     * 같은 이름이 있는 중복 회원 허가 X
     *
     * @param member
     * @return
     */
    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");
        }
    }

 

문제는 회원가입, 회원 조회에 시간을 측정하는 로직은 핵심 관심 사항이 아닌 공통 관심 사항이다.

이렇게 되면 *공통 관심 사항(시간 측정)*핵심 관심 사항(비즈니스 로직)이 섞여 코드의 유지 보수가 어려워진다. 그뿐만 아니라 나중에 밀리 세컨드 단위가 아니라 초 단위로 요구사항이 변경되면 코드의 수정도 어려워진다.

 

🍃 AOP 적용

AOP란 Aspect Oriented Programming의 약자로 말 그대로 '관점 지향 프로그래밍이다.'

쉽게 말하면 공통 관심 사항핵심 관심 사항을 분리하는 프로그래밍 패러다임이다.

 

이전 목차에서 살펴본 케이스에 AOP를 적용한다면 시간 측정 로직을 한곳에 정의하고 원하는 곳에만 적용할 수 있게 된다. 

 

@Aspect 어노테이션은 공통 관심 사항을 정의한 Aspect 클래스 붙이는 어노테이션이다.

@Around 어노테이션은 AOP를 어디에 적용할지 타겟팅하는 어노테이션으로 아래 코드에선 hellospring 패키지 산하의 모든 클래스에 적용한다.

 

 시간 측정 AOP

/**
 * @Aspect : AOP로 사용하도록 명시하는 어노테이션
 */
@Aspect
@Component
public class TimeTraceAop {
    /**
     * @Around : AOP를 어디에다 적용할지 타겟팅하는 어노테이션
     * hellospring 패키지 산하에 있는 모든 클래스에 적용
     */
    @Around("execution(* com.kangworld.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");
        }
    }
}

 

AOP가 동작하는 방식은?

비즈니스 로직에 AOP가 적용됐다면 Spring은 가짜 controller, service, repository인 proxy를 생성한다.

 

가령, AOP가 적용된 service의 join 메서드가 호출된다면 proxy memberService의 AOP(시간 측정)가 실행되고 joinPoint.proceed()를 호출한다. joinPoint.proceed()는 내부적으로 실제 service의 메서드를 실행함으로써 공통 관심 사항과 핵심 관심 사항을 분리할 수 있게 된다.