Spring 프레임워크를 공부하며, AOP(Aspect-Oriented Programming)가 뭐지?
이게 왜 필요한지? 필터랑 다른 게 뭔지?라는 궁금점이 생겼다.
오늘은 AOP에 대해 개념이랑 적용 방법에 대해 공유해 보려 한다.
AOP란?
AOP(관점 지향 프로그래밍)는 공통 관심 사항(부가 기능)을 핵심 로직과 분리해서 한 곳에서 관리하도록 해주는 프로그래밍 기법이다.
📌 왜 AOP가 필요한가?
프로그램을 개발하다 보면 반복적으로 사용되는 코드나 가독성이 떨어지는 로직들을 자주 마주하게 되는 것을 볼 수 있다.
AOP는 이러한 반복되는 코드들을 비즈니스 로직과 분리함으로써 중복을 줄이고, 코드의 유지보수성을 향상시키는 데 큰 도움을 준다.
예시)
public class UserService {
public void save(User user) {
log.info("사용자 저장 시도"); // 공통 관심사
// 사용자 저장 (핵심 관심사)
}
public void delete(User user) {
log.info("사용자 삭제 시도"); // 공통 관심사
// 사용자 삭제 (핵심 관심사)
}
}
예시를 보면 모든 메서드마다 log.info() 같은 부가기능이 계속 반복되는걸 볼 수 있다.
이런 부가기능 들을 변경하면 모든 클래스에 수정이 필요하므로 변경도 어렵다.
하지만, 공통 기능을 Aspect로 모아두고, 핵심 기능은 그대로 두면 유지보수가 훨씬 쉬워진다!
📌 AOP에서 사용하는 어노테이션 정리
어노테이션 | 설명 |
@Aspect | 이 클래스가 AOP를 정의하는 "관점(Aspect)" 클래스임을 나타낸다 |
@Component | Spring Bean으로 등록되기 위한 어노테이션이다. AOP 클래스는 반드시 스프링 컨테이너에서 관리되어야 하므로 필요합니다. |
@Pointcut | AOP를 적용할 지점(JoinPoint) 을 정의한다. 예: 특정 패키지의 메서드, 어노테이션이 붙은 메서드 등 |
@Before | 대상 메서드 실행 이전에 실행할 부가 기능(Advice)을 정의한다 |
@After | 대상 메서드 실행 후에(정상 또는 예외 상관 없이) 실행된다 |
@AfterReturning | 대상 메서드가 정상적으로 리턴된 후 실행된다. |
@AfterThrowing | 대상 메서드에서 예외가 발생했을 때 실행된다 |
@Around | 메서드 실행 전후를 모두 감싸서 동작한다. |
📌 왜 AOP에서는 log.info를 써야 할까?
- AOP를 활용해 로그를 출력할 때, 단순히 System.out.println()을 사용하는 것보다 log.info()와 같은 로깅 프레임워크(SLF4 J, Logback 등)를 사용하는 것이 좋다.
System.out.println()은 화면에 단순히 텍스트를 출력하는 명령으로, 로그 수준을 설정할 수 없지만, log.info(), log.debug(), log.error()와 같은 로깅은 로그 레벨을 구분해서 필요한 정보만 필터링하거나 출력할 수 있고, 로그를 파일에 남기거나 날짜별로 분리 저장을 할 수 있다.
콘솔 로그)
📌 Spring AOP의 동작 방식
- 스프링 컨테이너가 관리하는 Bean만 적용 대상
- 메서드 실행 시점에만 AOP 적용 가능 (JoinPoint는 오직 메서드)
- 내부적으로는 프록시 객체를 만들어 동작
📌 사용 예시
@Pointcut
@Pointcut("execution(* com.example.service..*(..))")
public void serviceMethods() {}
com.example.service 패키지 안의 모든 메서드를 AOP 대상으로 지정
@Before
@Before("serviceMethods()")
public void beforeAdvice(JoinPoint joinPoint) {
log.info("Before Method: {}", joinPoint.getSignature().getName());
}
메서드 실행 전에 로그를 출력
@AfterReturning
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
log.info("Method returned: {}", result);
}
메서드가 정상적으로 리턴되었을 때 결과값을 로그에 출력
@AfterThrowing
@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
log.error("Exception in method: {}, error: {}", joinPoint.getSignature().getName(), ex.getMessage());
}
예외 발생 시 로그를 출력
@Around
@Around("serviceMethods()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
log.info("Before method: {}", pjp.getSignature().getName());
Object result = pjp.proceed(); // 실제 메서드 실행
log.info("After method: {}", pjp.getSignature().getName());
return result;
}
메서드 전후에 커스텀 로직을 삽입할 수 있으며, 실행 흐름을 제어할 수 있는 강력한 기능이다.
AOP는 코드 곳곳에 반복되는 공통 로직을 깔끔하게 분리해서, 핵심 로직에만 집중할 수 있게 도와주는 개발자의 비서 같은 존재라고 생각하면 된다!!
'Spring' 카테고리의 다른 글
EC2 인바운드 규칙 미설정으로 인한 접속 불가 문제 (3) | 2025.05.27 |
---|---|
실전 프로젝트 - 도서 관리 앱 만들기 (4) | 2025.05.20 |
QueryDSL 의존성 설정 및 활용 (1) | 2025.05.13 |
DB 동시성 제어(비관적, 낙관적, 분산 락) (1) | 2025.05.02 |
Spring Boot 테스트, Mocking이란? (1) | 2025.05.01 |