https://tech.kakaopay.com/post/overcome-spring-aop-with-kotlin/ 에 대한 Review
최근 AOP를 활용하여 애노테이션을 하나 만든 것이 있다.
@ReadBatch 라는 애노테이션이었는데, 해당 애노테이션이 붙은 경우에는 ThreadLocal에 string value인 batch를 set하고, 실제 트랜잭션이 실행될 때 해당 쓰레드의 쓰레드로컬에 batch가 세팅되어있다면 batch db로 쿼리를 라우팅하는 용도였다.
AOP는 Aspect Oriented Programming으로 특정 메서드가 실행되기 전, 후에 중복되어 실행되어야하는 부분을 재사용할 수 있도록 분리해내는 프로그래밍 방법이다.
가장 간단한 예시가 @Transactional 애노테이션을 들 수 있다.
우리는 db에 cud 쿼리를 수행하기 전 트랜잭션을 열고, 마지막에 트랜잭션을 닫아주는 부분을 매번 작성해야한다. 하지만 해당 애노테이션만 메서드에 명시해준다면 해당 메서드가 실행되기 전/후로 트랜잭션을 열고 닫는 행위를 수행해준다.
이렇게 트랜잭션을 열고 닫는 로직, 즉 특정 메서드의 전후에 삽입되는 로직을 Advice, 로직이 삽입될 메서드를 JoinPoint라고 부른다.
위 링크한 pay tech 블로그 글을 통해 알게된 것이 trailing lambda라는 것이다. 이 문법은 마지막에 오는 함수 형태의 인자를 람다 식으로 변환하여 넘겨준다.
블로그의 예시를 가져와보자면 다음과 같다.
val result = delegate({1+3})
// using trailing lambda
val result = delegate {1 + 3}
이 Trailing Lambda를 활용하여 AOP를 간단히 구현할 수 있다.
만약 내가 위에서 언급한 @ReadBatch를 Trailing Lambda를 활용하면 아래와 같이 구현할 수 있을 것이다.
fun <T> readBatch(function: () -> T): T {
// before method
RoutingDataSource.context.set(RoutingDataSource.BATCH)
val result = function.invoke()
// after method
RoutingDataSource.context.remove()
return result
}
그리고 애노테이션 대신 다음과 같이 적용할 수 있다.
class SomeService {
fun getSomething() = readBatch {
// logic
}
}
Spring AOP를 사용하게 된다면 프록시로 동작하기 때문에 클래스 내부 함수 호출 시 AOP가 적용되지 않는다. 하지만 위 Trailing Lambda를 활용하면 함수형 프로그래밍 기법을 사용하기 때문에 내부 함수 호출 또한 AOP가 동작하도록 할 수 있다.
많은 도움이 되었습니다, 감사합니다.