본문 바로가기
JAVA & SPRING/Spring 입문

스프링 입문 강의 - 5일차(AOP)

by 눈오는1월 2023. 7. 20.
728x90

이제 이 입문강의에서 들을 수 있는 마지막 AOP에 대해서 정리하려고 한다.

보통 컴공 1학년이 C에서 포인터 부분을 나가게 되면 다들 이제 실력이 평등하게 된다고 한다는 말이 있다 스프링에서는 AOP가 이 역할을한다고 한다. 그만큼 어렵지만 중요하기때문에 열심히 공부를 해야하는 부분일 수도 있다.

AOP란 Aspect Oriented Programming 의 약자로 관점 지향 프로그래밍 이라고도 부른다고함

AOP를 왜써야되는지 어디서 필요한지에 대해 먼저 정리를 하면,

만약 의뢰인이 지금 현재 내가 만든 코드들의 시간을 측정해달라고 부탁했다고 쳐보자.

그럼 위 사진들처럼 3개 부분의  시간을 측정을 해야한다.

일단 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는 이러한 상황에서 공통 관심 사항과 핵심 관심 사항을 분리해서 일을 처리할 수 있게 해준다.

공통 과심 사항이란 -> 핵심 관심 사항이 아닌것으로 위에서 시간을 측정하는 것이 공통 관심 사항이고

핵심 관심 사항이란 -> 이 서비스의 핵심이 되는 사항으로 우리가 만든거에서는 회원 등록,회원 조회가 될 수 있다.

위 그림처럼 시간 측정 로직을 따로 만들어서 필요한 부분에 쓰일 수 있게끔 하는 것이다.

 

일단 우리가 만든 패키지들(controller,domain,repository..)와 같은 경로에 aop라는 패키지를 만들고 해당 패키지 안에

TimeTraceAop 클래스를 만든다.

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

Aspect 어노테이션을 이용해서 위 코드가 AOP인지 알려주고 컴포넌트 어노테이션을 붙여준다.

@Around("execution(* hello.hellospring..*(..))")는 패키지 하위에 다 적용해라 라는 뜻이다. 만약 모든 패키지말고 특정 패키지에 적용시키려면 문서를 참고해서 아래있는 문자를 바꿔주면된다.

 

위에서 하나하나 다 적용시켰던 부분을 이 클래스에 적용시키고 힐행을 하면 위와 같은 동일한 결과를 얻을 수 있다.

 

즉 우리는 핵심 관심 사항과 공통 관심 사항을 분리한뒤에 공통 관심 사항을 따로 로직을 별로로 만들었다.

이렇게 하면 핵심 관심 사항만 별로로 유지보수하는일이 가능하다.

 

AOP의 이론을 좀 더 설명을 하자면..(추후 강의에서 배우고 나서 좀 더 잘 정리할 예정)

 

AOP가 없을 때 의존관게는 

이런식으로 memberController 와 memberService가 직접적으로 연결되었으나 

AOP가 적용 된 의존관게를 보면 

위 그림처럼되는데 이러한 이유를 간략하게나마 설명하자면

스프링은 AOP를 지정하면 가짜 스프링 빈을 만들고 AOP가 실행된다. 이렇게 실행된 상태에서 joinPoint.proceed()를 만나면 진짜 서비스가 호출되는 형태이다.

그래서 전체적인 AOP 적용 전 후 의 차이를 그림으로 표현하자면 아래 그림들 처럼 표현된다.

AOP 적용 전
AOP 적용 후

위 그림처럼 될 수 있다.

 

김영한님의 스프링 입문 강의를 듣고 전반적인 스프링에 대해서 알게 되었다. 내가 아직 자바 OOP개념도 부족하고 백엔드 역량도 많이 부족하기 때문에 어렵게 느껴졌지만 김영한님께서도 이번강의의 목표는 스프링이 무엇인지에 대해서 넓게 학습하는게 목표라기에 어려워도 정리를 해서 학습을했고 확실히 정리하면서 진도를 나가니까 속도는 조금 느리더라도 조금씩은 머릿속에 정리된거 같다.

아직 많이 부족하지만 다음 강의도 듣고 이제 좀 더 깊게 공부하고 정리해나가야겠다.

그리고 강의내용이 너무 좋고 너무 친절하게 가르쳐주시고 잘 가르쳐주셔서 정말 감사드린다. 왜 다들 김영한님을 추천하는지 알 수 있었다.

 

728x90