[스프링 개발 입문] 7. AOP

HJ·2022년 7월 27일
0

김영한 님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 보고 작성한 내용입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard


24. AOP

24-1. AOP가 필요한 상황

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

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

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


24-2. ex> MemberService 회원 조회 시간 측정 추가


< MemberService >

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");
        }
    }
  • 문제점

    • 위처럼 모든 메소드에 하나씩 시간을 측정하는 코드를 추가해야함

    • 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다

    • 시간을 측정하는 로직은 공통 관심 사항이다 ( not 핵심 )

    • 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다

    • 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다

    • 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다


24-3. AOP 적용

  • AOP: Aspect Oriented Programming ( 관점 지향 프로그래밍 )

  • 핵심 관심 사항과 공통 관심 사항을 분리해서 작성해야함

  • 공통 관심 사항 로직을 작성하고 원하는 곳에 적용


24-4. ex> 시간 측정 AOP 등록


< TimeTraceAop >

@Aspect
@Component
public class TimeTraceAop {

    @Around("execution(* com.ghkwhd.project_2.*(..))")
    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를 나타내는 클래스임을 나타냄

  • 만들어진 AOP는 스프링 빈으로 등록해야하기 때문에 @Component를 사용 ( 컴포넌트 스캔을 이용 )

  • joinPoint.proceed() : 실제 메서드를 호출하고 return 되는 데이터를 받는다

  • joinPoint.toString() : 어떤 메서드를 수행하는지 반환해줌

  • @Around : AOP를 어디에 적용할 것인지 타켓팅

    • @Around("execution(* com.ghkwhd.project_2.*(..))") : 패키지 하위에는 모두 적용하는 코드

24-5. AOP 스프링 빈으로 등록


< SpringConfig >

    @Bean
    public TimeTraceAop timeTraceAop() {
        return new TimeTraceAop();
    }
  • AOP 작성 시 @Component를 붙이지 않는 경우에 사용 ( 컴포넌트 스캔을 사용하지 않는 경우 )

24-6. AOP 동작 방식

  • AOP를 작성하고 어디에 적용할 것인지를 지정하면 spring은 가짜(프로시)를 만든다

  • Spring Container는 스프링 빈을 동록할 때, 실제 스프링 빈이 아닌 가짜(프록시) 스프링 빈을 만들어 앞에 세워놓는다

  • 가짜(프록시) 스프링 빈이 끝나면 joinPoint.proceed()를 통해 실제 스프링 빈을 호출

  • ex> MemberController가 호출하는 것은 실제 MemberService가 아닌 프록시 MemberService

  • 프록시를 통해 AOP가 실행

  • 이전 게시글 참고 : https://velog.io/@hj_/Spring-Boot-30.-AOP-%EB%B6%80%EA%B0%80-%EA%B8%B0%EB%8A%A5-%EC%A3%BC%EC%9E%85

0개의 댓글