[스프링] AOP

gyeol·2023년 7월 7일

스프링

목록 보기
10/50
post-thumbnail

스프링 강의 5일차 😚

김영한님의 '스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술'을 듣고 적은 글입니다.

✔️ AOP

AOP가 필요한 상황 ➡️ 모든 메소드의 호출 시간을 측정하고 싶다면 ?
원래였다면 메소드마다 일일히 start, finish 타임을 측정해야했다.

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 를 적용하려고 한다. (원하는 곳에 공통 관심 사항을 적용하겠다는 것 !)

AOP :
Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이다. 어떤 로직을 기준으로 핵심적 관점, 부가적 관점으로 나누어 보고 그 관점을 기준으로 각각 모듈화한 것이다.

시간 측정 AOP 등록을 위해 aop라는 패키지를 만들고 그 안에 TimeTraceAop.java 파일을 만들어 준다.

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 적용 전 의존관계

🔹AOP 적용 후 의존관계

스프링 컨테이너는 AOP가 적용되면 프록시를 통해 AOP를 실행한다. 프록시는 간단히 말해 가짜 멤버 메소드를 의미한다. 스프링 컨테이너는 프록시를 먼저 앞으로 내세운다. 그리고 joinPoint.proceed() 를 통해 진짜 멤버 메소드를 호출한다.

AOP를 적용한 전체 그림을 살펴보면

각각 프록시를 통해 AOP를 실행하고난 후에야 실제 메서드들을 호출한 것을 볼 수 있다.

profile
공부 기록 공간 '◡'

0개의 댓글