[Spring Boot] AOP

Updated:

AOP가 필요한 상황

✅ 모든 메소드의 호출 시간을 측정하고 싶다면?

✅ 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)

✅ 회원 가입 시간, 회원 조회 시간을 측정하고 싶다면?

image


service/MemberService.javaMemberService 회원 조회 시간 측정을 추가

join 메소드의 코드를 아래와 같이 수정

public Long join(Member member) {

    long start = System.currentTimeMillis(); // millisecond로 받을 수 있음

    // 로직이 끝날 때 시간을 찍어야 함
    try {
        validateDuplicateMember(member); // 중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    } finally { // 예외가 생겨도 시간 출력
        long finish = System.currentTimeMillis();
        long timeMs = finish - start;
        System.out.println("join = " + timeMs + "ms");
    }
}

테스트를 돌려보자

Screen Shot 2022-04-14 at 3 21 56 PM

Screen Shot 2022-04-14 at 3 22 07 PM


회원 조회 메소드에도 시간 측정 코드 추가

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

서버를 실행하고 시간이 출력 되는지 확인

Screen Shot 2022-04-14 at 3 26 40 PM

Screen Shot 2022-04-14 at 3 27 07 PM

⬆️ 처음 돌릴땐 오래걸리고, 두번째 실행할 땐 시간이 줄어든다.

등록도 해봤다.

Screen Shot 2022-04-14 at 3 30 24 PM


❗️문제

  • 회원가입, 회원 조회에 시간을 측정하는 기능핵심 관심 사항이 아니다.
  • 시간을 측정하는 로직은 공통 관심 사항이다.
  • 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다.
  • 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다.

AOP 적용

AOP : Aspect Oriented Programming, 관점지향 프로그래밍 공통 관심 사항(Cross-cutting concern) vs 핵심 관심 사항(core concern) 분리

위에서는 시간측정 로직들을 메소드에 다 붙였다. ➡️ 이젠 AOP로 시간 측정 로직을 한 곳에 모으고 원하는데 적용

image

시간 측정 AOP 등록

src/main/java/com.example.memberproject/aop 패키지 생성 후,TimeTraceAop.java 작성

 package com.example.memberproject.aop;

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

@Aspect
@Component // 컴포넌트 스캔으로 등록해도 됨
// 컴포넌트 스캔보다 스프링 빈에 등록해서 쓰는것을 더 선호 -> SpringConfig에서 등록
public class TimeTraceAop { // 이 클래스를 스프링 빈으로 등록해줘야 함

    @Around("execution(* com.example.memberproject..*(..))") // 어떤 메소드에 적용할 것인지 타겟팅할 수 있음
    public Object execut(ProceedingJoinPoint joinPoint) throws Throwable {
        // 시간 로직
        long start = System.currentTimeMillis();
        System.out.println("STRAT: " + joinPoint.toString()); // 어떤 메소드를 call 하는지 이름을 얻어올  수 있음
        try {
            // 다음 메소드로 진행
            // Object result = joinPoint.proceed();// 다음 메소드로 진행
            // return result;
            return joinPoint.proceed(); // 인라인으로 변경

        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
        }
    }
}

서버를 실행하고 결과를 확인해보자

Screen Shot 2022-04-14 at 3 56 40 PM

잘 출력 되는 것을 볼 수 있다.


MemberService.java 에서 시간 측정 로직을 지우고 원래대로 돌려놓기 !

Screen Shot 2022-04-14 at 3 59 47 PM


호출이 될 때마다 joinPoint의 파라미터를 사용해서 조작할 수 있다. 메서드를 호출할 때마다 인터셉트가 걸리는 것


해결

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

스프링 AOP 동작 방식 설명

AOP 적용 전 의존관계

Screen Shot 2022-04-14 at 4 12 56 PM

➡️ helloController가 memberService에 의존하고 있고, helloController에서 memberService의 메소드를 호출

➡️ 의존관계가 있고 그냥 호출했다.


AOP 적용 후 의존관계

Screen Shot 2022-04-14 at 4 13 35 PM

➡️ AOP가 있으면 스프링은 가짜 memberService를 만든다. = 프록시

➡️ 스프링이 올라올 때, 컨테이너에 스프링 빈을 등록할 때, 진짜 스프링 빈이 아니라 가짜 스프링 빈을 앞에 세워 놓는다.

➡️ 가짜 스프링 빈이 끝나면, joinPoint.proceed() 하면 내부적으로 타고, 그때 실제 memberService를 진짜로 호출

➡️ helloController가 호출하는 것은 진짜 memberService가 아닌 프록시라는 기술로 발생하는 가짜 memberService이다.

실제 Proxy가 주입되는지 콘솔에 출력해보기

⬇️ MemberController.java의 생성자에서 찍어보면 아래와 같이 나온다.

memberService = class com.example.memberproject.service.MemberService$$EnhancerBySpringCGLIB$$7ca48fe3

보면 memberService로 끝나는 것이 아니라 \(EnhancerBySpringCGLIB\)7ca48fe3 이런게 붙어서 나온다. EnhancerBySpringCGLIB는 MemberService를 복제를 해서 코드를 조작하는 기술이다.


AOP 적용 전 전체 그림

Screen Shot 2022-04-14 at 4 27 26 PM


AOP 적용 후 전체 그림

Screen Shot 2022-04-14 at 4 27 51 PM

정리

H2 데이터 베이스 : 실무에서 로컬 db로 많이 쓴다. 실제 운영은 mysql 계열, jpa 를 쓰면 이런걸 바꿔치기할 수 있기 때문 jpa가 쿼리를 db에 맞춰서 sql을 만들어준다.


스프링을 어떻게 시작해야 하는지 막막했었는데, 좋은 무료 강의와 윤경님의 잘 정리된 블로그를 참고하면서 공부할 수 있었다 ㅎㅎ… 엄청 거대한 스프링… 아직 많이 모르지만,,, 열심히 해보자..!!

🟢 스프링의 흐름을 파악하자 ➡️ 전반적인 지도 그리기

🟢 각각의 기술들을 깊이있게 이해하자

🟢 스프링을 활용해서 실무에서 발생하는 문제들을 잘 해결하는 것이 훨씬 중요

🟢 핵심 원리를 이해하고, 문제가 발생했을 때, 대략 어디쯤 부터 찾아들어가면 될지, 필요한 부분을 찾아서 사용할 수 있는 능력!!

참고

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

YoonkyungH.log

Leave a comment