반응형

https://tech.kakaopay.com/post/overcome-spring-aop-with-kotlin/

 

Kotlin으로 Spring AOP 극복하기! | 카카오페이 기술 블로그

Kotlin의 문법적 기능을 사용해서 Spring AOP 아쉬운 점을 극복한 경험을 공유합니다.

tech.kakaopay.com

이번 글은 해당 기술 블로그를 참고하였습니다.

 

현재 프로젝트에 유저 서비스에는 다음과 같은 메서드들이 있다.

 

이런 메서드를 호출 할 때마다, session에서 userId를 가져와 로그로 남기고 싶다.

 

그러면 해당 메서드에 하나하나 userId를 가져와서 로그를 남기는 코드를 추가해야 할까?

이럴 경우에는 하나하나 작성하는 것에 시간도 오래 걸리고, 변경사항이 생기면 다 찾아서 바꿔야 할 것임으로 굉장히 비효율적이다.

 

이럴 때, AOP의 개념을 사용하면 된다.

 

AOP(Aspect Oriented Programming)란?

여러 모듈이나 메서드에서 공통적으로 나타나는 공통 관심사항을 추출하여 공통 로직으로 관리하는 것이다.

 

그럼 이렇게 유저 아이디를 로그로 남기자! 라는 관심사를 분리하여 처리해보자.

 

    //AOP
    implementation("org.springframework.boot:spring-boot-starter-aop:3.1.2")

 

우선 코틀린에 이런 의존성을 추가해준다.

 

그 다음엔 이런 annotation을 추가해준다.

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class LoginCheck

 

아마 위에 추가하는 annotation의 value들이 자바와는 좀 다를거다.

 

그 다음에는 해당 annotation으로 로그를 출력하는 component이다.

@Aspect
@Component
class LoginCheckAspect {

    companion object {
        private val log = LoggerFactory.getLogger(LoginCheckAspect::class.java)
    }

    @SneakyThrows
    @Around("@annotation(seungkyu.board.aop.LoginCheck)")
    fun adminLoginCheck(joinPoint: ProceedingJoinPoint):Any? {
        val startAt = LocalDateTime.now()
        log.info("Start At : $startAt")

        (joinPoint.args[0] as ServerRequest)
            .session()
            .doOnNext {
                log.info("id: {}", it.attributes["id"])
            }.subscribe()


        val proceed = joinPoint.proceed()

        val endAt = LocalDateTime.now()

        log.info("End At : $startAt")
        log.info("Logic Duration : ${Duration.between(startAt, endAt).toMillis()}ms")

        return proceed
    }
}

 

우선 클래스에 @Aspect, @Component annotation을 달아준다.

 

그 다음에는 출력하는 메서드를 작성하는데, 메서드 위에도 @annotation({해당 annotation의 패키지 위치})로 @Around를 작성해준다.

 

보통은 여기에서 다들 시간을 출력하기에 시간도 출력해보았다.

startTime을 joinPoint.proceed() 전으로, endTime을 joinPoint 후로 측정하면 해당 logic의 소요 시간을 측정할 수 있다.

 

그 다음으로는 session으로부터 id를 가져올건데, 우리가 사용하는 서비스 메서드의 parameter를 잘 봐야 한다.

 

override suspend fun getUserInfo(request: ServerRequest): ServerResponse

 

보통 이렇게 parameter가 serverRequest 하나이다.

 

그렇기에 joinPoint.args에서 0번째 Index를 가져와서 ServerRequest로 casting 해주면 그 안에서 session을 가져올 수 있다.

그렇게 가져온 session은 Mono타입이기 때문에 doOnNext로 해당 userId를 출력해줬다.

 

 

이렇게 원하는 대로 userId가 로그로 출력된 것을 볼 수 있다.

+ Recent posts