스프링 프레임워크는 객체지향 설계 원칙을 충실히 따르면서도,
공통 관심 사항을 코드에서 분리해낼 수 있는 강력한 기능을 제공한다.
그 기능이 바로 AOP (Aspect Oriented Programming), 즉 애스펙트 지향 프로그래밍이다.
애스펙트란?
애스펙트는 공통 로직을 핵심 로직과 분리하여 모듈화 하기 위한 개념이다.
예: 로그 기록, 보안 검사, 트랜잭션 처리 등은 여러 서비스에서 반복적으로 사용되지만,
이걸 모든 메서드마다 작성하면 중복되고 가독성이 떨어진다.
이런 로직을 하나로 묶고 실행 흐름에 자동으로 삽입하면? → 바로 AOP의 장점이 드러난다.
스프링 AOP 의 작동 방식
스프링 AOP는 아래 세가지 구성요소를 기반으로 작동한다.
Aspect | 실행하고 싶은 공통 기능을 정의하는 클래스이다. |
Advice | 언제 실행할지를 정의하는 설정이다. (@Before, @After, @Around 등) |
Pointcut | 어떤 메서드에 적용할지를 정의하는 조건이다. |
코드 예제
1. 커스텀 애너테이션: @ToLog
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ToLog {}
→ 로그를 남기고 싶은 메서드에 이 애너테이션만 붙이면 자동으로 애스펙트가 동작하게 된다.
2. 비즈니스 로직 CommentService
@Service
public class CommentService {
private final Logger logger = Logger.getLogger(CommentService.class.getName());
private Comment comment;
@ToLog
public void publishComment(Comment comment) {
this.comment = comment;
logger.info("Publishing comment: " + comment.getText());
}
}
→ @ToLog를 붙이면 이 메서드를 호출할 때마다 LoggingAspect와 SecurityAspect가 실행된다.
3. 실행 전후 로깅 LoggingAspect
@Aspect
@Order(2)
public class LoggingAspect {
private final Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Around("@annotation(ToLog)")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Logging Aspect 시작");
Object result = joinPoint.proceed(); // 다음 애스펙트 또는 실제 메서드 호출
logger.info("Logging Aspect 끝, 결과: " + result);
return result;
}
}
4. 접근 제어 Security Aspect
@Aspect
@Order(1)
public class SecurityAspect {
private final Logger logger = Logger.getLogger(SecurityAspect.class.getName());
@Around("@annotation(ToLog)")
public Object secure(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Security Aspect 실행");
Object result = joinPoint.proceed();
logger.info("Security Aspect 통과");
return result;
}
}
@Order 를 통해 애스펙트 실행순서를 조절할 수 있다.
Main 호출 → SecurityAspect → LoggingAspect → CommentService.publishComment
애스펙트에서 할 수 있는 일
- 메서드 호출 전/후 로직 삽입
- 매개변수 변경
- 반환값 변경
- 예외 감지 및 처리
- 로깅, 보안 검사, 트랜잭션 처리
애스펙트 사용시 주의사항
빈 등록 | @Aspect만 붙이면 동작하지 않는다. 반드시 @Configuration 클래스에서 직접 Bean으로 등록해야 한다. |
프록시 대상 | 애스펙트를 적용할 클래스는 반드시 스프링 컨텍스트에 등록된 빈이어야 한다. |
내부 메서드 호출 | 같은 클래스 내부에서 메서드 호출 시 프록시를 거치지 않아 애스펙트가 적용되지 않는다. |
정상 흐름 유지 | 가로채서 반환값을 바꾸면 시스템에 부작용이 발생할 수 있으므로 꼭 필요한 경우에만 사용해야 한다. |
순서 지정 | 여러 애스펙트를 사용하는 경우, 실행 순서를 명확히 지정해야 한다 (@Order). |
마무리
Spring AOP는 공통된 로직을 분리하고, 비즈니스 로직의 가독성과 유지보수성을 높이는 데 효과적인 도구이다.
- 반복되는 로깅
- 보안 검사
- 트랜잭션 처리
- 성능 측정
- 예외 처리
이런 기능들을한 곳에서 선언하고, 자동으로 실행되게 만들면 코드가 훨씬 깔끔해진다.
다만, 적재적소에 신중히 사용하는 것이 핵심이다.
'스프링' 카테고리의 다른 글
스프링에서 데이터베이스 다루기 3 - 스프링 데이터로 간결한 영속성 계층 개발 (0) | 2025.04.05 |
---|---|
스프링 부트와 스프링 MVC 이해 (0) | 2025.04.05 |
스프링에서 데이터베이스 다루기 2 – 사용자 정의 DataSource 설정 (0) | 2025.04.03 |
스프링에서 데이터베이스 다루기 1 - JDBC (0) | 2025.04.02 |
스프링에서 다른 서버 API 호출하기 (0) | 2025.04.02 |