[스프링 입문] Section 07 - AOP

Update:     Updated:

카테고리:

태그:

AOP란?

AOP는 Aspect Oriented Programming의 약자로 ‘관점 지향 프로그래밍’이라고 불린다.
관점 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다.

AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 모듈화하겠다는 의미다.
이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사 (Crosscutting Concerns)라 부른다. 

위와 같이 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지다.

AOP가 필요한 상황

‘모든 메소드의 호출 시간을 측정하고 싶다!’는 상황을 가정해보자.
시간 측정 로직은 ‘핵심 관심 사항’과 ‘공통 관심 사항’ 중 공통 관심 사항에 해당할 것이다.

- 그냥 해보자..

Image

package hello.hellospring.service;

@Transactional
public class MemberService {
    
    /**
    * 회원가입
    */
    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");
        } 
    }

    /**
    *전체 회원 조회
    */
    public List<Member> findMembers() {
        long start = System.currentTimeMillis();
        try {
            return memberRepository.findAll();
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("findMembers " + timeMs + "ms");
        } 
    }
}

자, 이렇게 되면 문제가 무엇이냐?
일단, 기능 별로 하나 하나씩 직접 코드를 넣어준다는 것은 말이 안 된다.
또, 시간을 측정하는 기능은 핵심 관심 사항이 아닌 공통 관심 사항이다.
따라서, 이렇게 시간 측정 로직과 핵심 비즈니스 로식이 섞이게 되면 추후 유지보수가 힘들어진다.

- AOP를 적용 해보자..!

Image

앞선 문제 상황을 공통 관심 사항과 핵심 관심 사항을 분리하여 해결해보자!

package hello.hellospring.aop;

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

@Component
@Aspect
public class TimeTraceAop {
    
    @Around("execution(* hello.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 적용 전

Image

- AOP 적용 후

Image

Reference

1) https://www.inflearn.com/questions/48156
[AOP(TimeTraceAop)를 @Component 로 선언 vs SpringConfig에 @Bean으로 등록]
2) https://engkimbs.tistory.com/746 [[Spring] 스프링 AOP (Spring AOP) 총정리 : 개념, 프록시 기반 AOP, @AOP]

Spring-Tutorial 카테고리 내 다른 글 보러가기

댓글 남기기