[우아한테크코스] 8월 8일 TIL

1 minute read

[Spring] AOP를 이용한 커스텀 어노테이션

Proxy Pattern

디자인 패턴 중 하나로 실제 객체에 대한 interface 역할을 수행하는 class의 객체

spring aop에서는 spring bean이 만들어질 때 spring aop가 proxy를 자동으로 만들고 기존 클래스 대신 proxy를 bean으로 등록하고 기존 클래스가 사용될 때 proxy를 사용한다.

예를 들어 MemberService bean에 @Transactional 이 붙어있다면 MemberService 타입의 proxy가 만들어지고, 실행 시점에 @Transactionl 어노테이션이 지시하는 코드가 들어간다.

proxy는 직접 책임을 수행하지 않고 실제 객체를 감싸서 client와의 중계역할을 하는 wrapper로 사용된다. 실제 객체가 대신 처리하도록 위임한다.


AOP

관점 지향 프로그래밍으로 핵심 기능과 공통 기능을 나누고 핵심 기능에서 공통 기능을 불러와서 사용

  • 생각하게 된 이유?

성능 측정을 하는데 코드에 들어가야하는 것이 불편하다!

중복된 코드가 늘어나고 빼먹기 쉽상이다!

AOP 용어

  • advice: target 클래스의 jointpoint에 들어가 동작할 코드

  • Jointpoint: advice를 적용할 시점(메서드 호출, exception 발생 등)

  • pointcut: jointpoint의 집합으로 advice가 적용되는 jointpoint

  • weaving: advice를 핵심 로직에 적용하는 것

  • aspect: 여러 객체에 공통으로 적용되는 관심 사항(aop에 좋은 것)

  • Target: 핵심 로직 구현 클래스, advice 받는 대상

  • advisor: advice + point cut

  • Proxy: advice가 적용된 후 생성된 객체


  1. 메인 메서드에 어노테이션 추가
@SpringBootApplication
@EnableAspectJAutoProxy
public class ZzimkkongApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZzimkkongApplication.class, args);
    }
}

@EnableAspectJAutoProxy 란?


  1. 설정할 클래스 만들기
@Component
@Aspect
public class PerformanceConfig {
    @Around("within(com.woowacourse.zzimkkong.controller)")
    public Object checkPerformance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        long startAt = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        long endAt = System.currentTimeMillis();

        System.out.println(endAt - startAt);
        return result;
    }

@Component : bean 등록

@Aspect : 별도로 advice와 pointcut을 명시하지 않고도 advice 적용

@Around : pointcut 지정(execution: 메서드 지정, within: 패키지 지정)

ProceedingJoinPoint : advice 적용 대상


  1. 커스텀 어노테이션 만들기
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
@Documented
public @interface PerformanceLogging {
}

@Retention(RetentionPolicy.CLASS) : 어느 시점까지 어노테이션 메모리 가져갈지 지정(SOURCE: 컴파일, CLASS: LoadTime, RUNTIME: 런타임)

@Target(ElementType.METHOD) : target의 대상 타입 지정(METHOD, FIELD, PACKAGE, TYPE ..)

@Documented : javaDoc에 포함

어노테이션을 만들었으면 PerfomanceConfig 내용을 해당 어노테이션에 적용하도록 한다.

within -> @annotation

@Around("@annotation(PerformanceLogging)")

이 경우, main 클래스에 @EnableAspectJAutoProxy 등록도 불필요하다.


zzimkkong space - reservation 성능 측정 결과

  단방향 양방향 jpql 없으면 find 쿼리 양방향 한번에 모든 reservation (lazy) 양방향 한번에 모든 reservation (eager)
공간 조회 37 322 32 1835
모든 공간 조회 31 367 36 1306
특정 공간 예약 조회 382 372 1186 1145
모든 예약 조회 314 356 1129 1964