AOP란 무엇일까?
AOP(Aspect-Oriented Programming)는 관점 지향 프로그래밍이라고 부른다. 너무 어려운데 풀어서 설명하면 프로그램의 핵심 로직과 공통 기능(예 : 로깅, 보안, 트랜잭션 관리)을 분리하여 작성할 수 있도록 도와주는 것이라고 보면 된다.
즉, 핵심 비즈니스 로직에 영향을 주지 않으면서도 여러 곳에서 반복되는 기능을 한 곳에 모아서 관리할 수 있게 해준다(너무 좋은것 아닌가?)
더 쉽게 예를 들어 학교에서 학생들이 공부하는 주요 수업(핵심 로직)이 있다고 해보자. 그런데, 시험 감독, 출석 체크, 학부모 연락 등과 같은 공통 작업도 있는데, 이 작업들은 모든 수업에 걸쳐 반복된다.
AOP는 이처럼 "공통 작업(예 : 시험 감독)" 을 한 곳에서 관리하고, 각 수업(비즈니스 로직)에서는 신경 쓰지 않도록 분리하는 역할을 한다.
AOP의 주요 개념
- Aspect (관점) : AOP의 핵심 모듈로, 여러 곳에 적용할 공통 기능을 모아둔 단위이다. 예를 들어, 로깅 Aspect는 애플리케이션 전반에 걸쳐 로그를 기록하는 기능을 한 곳에 모아서 관리한다.
- Join Point (조인 포인트) : Aspect가 적용될 수 있는 지점을 의미한다. 메서드 호출, 예외 발생 등이 Join Point가 될 수 있다.
- Pointcut (포인트컷) : 어떤 Join Poin에 Aspect(Advice)를 적용할 것인지 정하는 조건이다. "어떤 메서드가 호출될 때마다 로그를 남겨라"와 같은 조건을 정의한다.
- Advice (어드바이스) : 실제로 수행되는 작업이다.
- Weaving (위빙) : Aspect를 실제 코드에 적용하는 과정이다. Srping AOP는 런타임(실행 시)에 동적으로 위빙을 수행하여, 개발자가 별도로 공통 기능 코드를 삽입하지 않아도 자동으로 적용된다.
Spring Boot 에서 Spring AOP 설정
별도의 XML 설정 없이, spring-boot-stater-aop 의존성을 추가하기만 하면 AOP 기능을 사용할 수 있다.
build.gradle 예시
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter'
}
간단한 로깅 Aspect 예시
메서드 실행 전후에 로그를 남기는 간단한 예시
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
@Aspect
@Component
class LoggingAspect {
private val logger = LoggerFactory.getLogger(this.javaClass)
// 모든 Service 패키지 내의 모든 메서드 실행 시점에 적용
@Around("execution(* com.example.service.*.*(..))")
fun logAround(joinPoint: ProceedingJoinPoint): Any? {
val methodName = joinPoint.signature.name
// 로그 출력 예시: "메서드 시작: getUserById"
logger.info("메서드 시작: $methodName") // 예시 로그: [INFO] 2025-02-26 12:34:56 - 메서드 시작: getUserById
try {
val result = joinPoint.proceed() // 실제 메서드 실행
// 로그 출력 예시: "메서드 종료: getUserById"
logger.info("메서드 종료: $methodName") // 예시 로그: [INFO] 2025-02-26 12:34:57 - 메서드 종료: getUserById
return result
} catch (e: Throwable) {
// 로그 출력 예시: "메서드 오류: getUserById, 예외: NullPointerException"
logger.error("메서드 오류: $methodName, 예외: ${e.message}") // 예시 로그: [ERROR] 2025-02-26 12:34:57 - 메서드 오류: getUserById, 예외: NullPointerException
throw e
}
}
}
- @Aspect: 이 클래스가 Aspect임을 선언한다.
- @Component: Spring의 빈으로 등록하여 자동으로 관리한다.
- @Around: 지정한 Pointcut(여기서는 com.example.service 패키지의 모든 메서드)에 대해, 메서드 실행 전후로 Advice를 실행한다.
- joinPoint.proceed(): 실제 메서드 호출을 진행하는 부분으로, 이 전후로 로그를 남겨 전체 실행 흐름을 모니터링한다.
이렇게 작성한 Aspect는 지정된 패키지 내의 모든 메서드 실행 시 자동으로 로그를 남긴다.
서비스 클래스 예시
package com.example.service
import org.springframework.stereotype.Service
@Service
class UserService {
fun getUserById(id: Long): User {
// 사용자 조회 로직...
return User(id, "Alice")
}
}
이때 getUserById 메서드가 호출되면, Aspect의 joinPoint.signature.name은 "getUserById"를 반환하게 되고, 로그에도 "메서드 시작: getUserById"와 같이 출력된다.
하지만 이런 AOP를 사용시 주의할 점이 있다.
- 과도한 사용 주의 : 너무 많이 사용하면 코드의 흐름을 파악하기 어려울 수 있다.
- 디버깅 어려움 : AOP에 의해 동적으로 적용된 로직은 디버깅 시 실제 코드 흐름을 파악하기 어렵게 만들 수 있다.
- 성능 고려 : Aspect가 많은 경우, 메서드 호출 전후에 추가적인 처리 시간이 발생할 수 있으니 성능에 미치는 영향을 고려해야한다.
'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글
Spring Boot와 Kotlin 백엔드 서버에서 로그 관리하기(2) (0) | 2025.03.19 |
---|---|
Spring Boot와 Kotlin 백엔드 서버에서 로그 관리하기 (3) | 2025.03.17 |
Spring Boot Auto Configuration 이해해보기 (2) | 2025.03.10 |
Kotlin의 Null Safety (2) | 2025.03.08 |
Kotlin 기본 문법 (1) | 2025.03.05 |