스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 [AOP]

윤현우·2023년 1월 6일
0
post-thumbnail

AOP

AOP란, Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불리는 스프링 3대 요소중 하나이다. 그리고 흩어진 Aspect를 모듈화할 수 있는 프로그래밍 기법입니다.

요번 게시글에서는 AOP를 간단한 예제를 통해서 알아보자. 자세한 내용은 나중에 다시 다루는 걸로 한다.

가장 유명한 예시로는 실행시간 출력 예제이다.


AOP 예제

모든 메서드의 호출시간을 출력해야 할 때 각각의 메서드에 시간 측정 로직을 작성해야한다.

MemberService 회원 조회 시간 측정 추가

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 적용

공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern) 분리한다.

시간 측정 AOP 등록

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"); }
			}
    }
          
          

@Component

  • AOP를 사용하는 클래스에 스프링 빈 설정을 해야한다
  • @Component를 사용하거나 @Configuration, @Bean 어노테이션을 이용하여 직접 생성한다.

@Aspect, @Around

  • 프록시를 만들기 위한 어노테이션
  • (다음에 더 자세히 설명하겠다.)

해결

  • 회원가입, 회원 조회등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.
  • 핵심 관심 사항을 깔끔하게 유지할 수 있다.
  • 변경이 필요하면 이 로직만 변경하면 된다.
  • 원하는 적용 대상을 선택할 수 있다.

이렇게 시간측정로직을 한 곳으로 모아 각각의 메서드에 뿌려준다. 만약 시간측정로직에 변경이 필요하면 한 곳만 수정을 하면 된다.


스프링의 AOP 동작 방식 설명

AOP 적용 전 의존관계

AOP 적용 후 의존관계

AOP 적용 전 전체 그림

AOP 적용 후 전체 그림

AOP는 각각의 클래스에 프록시를 생성해서 로직을 구현한다. 자세한건 이후 게시물에서 설명하겠다.


References (참고 자료)
https://www.inflearn.com

profile
개발자가 되는 그날까지

0개의 댓글