Spring Boot_AOP 적용

이세미·2023년 5월 22일
0

SpringBoot

목록 보기
23/23
post-thumbnail

AOP

:Aspect Oriented Programming
/공통 관심 사항과 핵심 관심 사항을 분리

시간 측정 로직을 TimeTraceAop라는 곳에 모아놓고,
helloController든, memberService든, memberRepository든
내가 원하는 곳에 적용해줌.

시간 측정 AOP 등록

우선 hello - helloSpring에 aop라는 패키지를 하나 생성하였다.
그리고 그 밑에 TimeTraceAop라는 클래스를 생성하였다.

AOP는 @Aspect라는 애노테이션을 필요로 하기 때문에 적어주었고,

public Object excute(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 없이 했던 코드와 비슷하게 진행된다.

return joinPoint.proceed(); 는
Object result = joinPoint.proceed()
return result
를 Inline으로 Refactor 해준 것이다.

joinPoint.proceed()는
다음 메소드로 진행하게 해준다.

이제 등록을 하기 위해서는
TimeTraceAop에 @Component 라는 애노테이션을 적는 방법과,

더 좋은 방법은
SpringConfig의 springbean에 등록을 하는 것이다.

@Bean
    public TimeTraceAop timeTraceAop() {
        return new TimeTraceAop();
    }

이렇게 스프링 빈에 직접 등록을 하는 방법이
확실하게 Aop가 등록돼서 쓰이는 구나 를 알 수 있기 때문에 더 좋은 방법이다.

여기서는 그냥 @Component를 사용하겠다.

그리고 이제 이 공통 관심 사항을 '어디에' 적용할 것인지를 targeting 해주기 위해

@Around("execution(* hello.hellospring..*(..))")

를 적어준다.
hello.hellospring의 모든 하위 패키지에 적용한다는 뜻이다.
여기에는 클래스명도 적을 수 있고 여러가지 다양한 것들을 적을 수가 있다.

예를 들어 service와 service 하위만 측정하고 싶으면,

@Around("execution( hello.hellospring.service..(..))")

이렇게 적어주면 된다.

이렇게 코드를 작성한 후,
실행을 시켜보았다.

HelloSpringApplication을 돌려서
서버를 띄우고,
회원 목록에 들어가본 후,
실행 결과를 보니

이렇게 MemberController, MemberService, JpaRepository들이 딱딱 나오고,

END: execution(List org.springframework.data.jpa.repository.JpaRepository.findAll()) 97ms

DB에서 조회하는 것 - 97ms

END: execution(List hello.hellospring.service.MemberService.findMembers()) 105ms

MemberService - 105ms

END: execution(String hello.hellospring.controller.MemberController.list(Model)) 121ms

MemberController - 121ms

이렇게 모두 나오는 것을 볼 수 있다.

이렇게 하면 어디에서 병목현상이 있는지 찾을 수가 있다.

호출이 될 때마다 joinPoint.로 원하는 것을 조작할 수 있다.

joinPoint가 다음으로 호출을 해주면서, intercept 가 걸리는 것이다.

이런 식으로 intercepting해서 풀어나갈 수 있는 이러한 기술이 바로 AOP이다.

이렇게 해서,
AOP를 사용하지 않고 시간을 측정했을 때 발생했던 문제들을
해결할 수 있는 것이다.

해결

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

스프링의 AOP 동작 방식 설명

AOP를 적용하기 전의 의존관계는,

helloController가 memberService를 의존하고 있고,
의존 관계에 의해 호출을 했을 것이다.

그런데 AOP에서는

적용할 위치를 지정을 하면,
프록시라고 하는 가짜 memberService를 만들어 내고,

컨테이너에 스프링 빈을 등록할 때,
진짜 스프링 빈 말고
가짜 스프링 빈 앞에 세워놓는다.
그리고 가짜 스프링 빈이 끝나면(joinPoint.proceed())
그때 진짜를 호출해 준다.

그래서
helloController가 호출하는 것은
진짜 memberService가 아닌
프록시라는 가짜 memberService인 것이다.

실제 Proxy가 주입되는지 콘솔에 출력해서 확인하기

controller - MemberController에

 @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
        System.out.println("memberService = " + memberService.getClass());
    }

이렇게 코드를 추가해 주었다.

결과는 가짜 memberService가 호출된 것을 확인해 볼 수 있었다.

<AOP 적용 전 전체 그림>

<AOP 적용 후 전체 그림>

0개의 댓글