BlueNyang
[Spring Boot] AOP, 모듈 분리와 무엇이 다른가?
Spring

[Spring Boot] AOP, 모듈 분리와 무엇이 다른가?

BlueNyangBlueNyang
·
·
약 6분
·
# aop# oop# cross-cutting-concerns# weaving# pointcut

Spring을 공부하다 보면 반드시 마주치는 개념이 있다. 바로, AOP(Aspect Oriented Programming) 이다.

공부를 하기위해 개념을 찾아보면, 다음과 같이 설명하고 있다.

Note
AOP는 관점 지향 프로그래밍으로, OOP(객체 지향 프로그래밍)와는 다른 패러다임을 제공한다. Spring Boot에서는 AOP를 통해 횡단 관심사를 효과적으로 관리할 수 있다. AOP는 OOP와 달리, 핵심 비즈니스 로직과 횡단 관심사를 분리하여 코드의 모듈화와 재사용성을 높인다.

이 정의를 보면, OOP와 AOP가 다른 패러다임이라는 것은 이해할 수 있다. 하지만, 모듈화와 재사용성이라는 측면에서 보면, OOP도 충분히 모듈화와 재사용성을 제공한다. 그렇다면, AOP는 OOP와 무엇이 다르기에, 굳이 새로운 패러다임으로 분류하는 것일까? 즉, 초보 개발자로써 던질 수 있는

"그래서, 그게 객체 지향 프로그래밍과 뭐가 다른데?"

라는 질문에 대한 답을 꼬리에 꼬리를 물고, 알아본다.

이 글은, 필자가 AOP의 필요성에 대해 가졌던 의문부터, OOP와의 결정적인 차이를 이해하고, 'Aspect(관점)'라는 개념을 통해 AOP의 개념을 머릿속에 정립하기까지의 과정을 정리한 기록이다.

1. Aspect Oriented Programming

AOP(Aspect Oriented Programming)은 직역하면 '관점 지향 프로그래밍'이다. 쉽게 말해, 애플리케이션의 핵심 비즈니스 로직에서 공통적으로 반복되는 부가 기능들을 분리하여 모듈화하는 프로그래밍 패러다임이다.

OOP(Object Oriented Programming, 객체 지향 프로그래밍)가 비즈니스 로직을 중심으로 모듈화하는 것이라면, AOP는 그 비즈니스 로직을 도와주는 공통 기능들을 중심으로 모듈화한다는 점에서 차이가 있다.

1.1. 핵심 기능과 부가기능(횡단 관심사)이란?

애플리케이션의 로직은 크게 두 가지로 나눌 수 있다.

  • 핵심 기능(Core Functionality): 애플리케이션의 주요 목적을 수행하는 기능. 예를 들어, 주문하기, 결제하기, 회원가입 등이 핵심 기능에 해당한다. 즉, 객체가 수행해얄하는 고유의 목표라고 할 수 있다.
  • 부가기능(Cross-Cutting Concerns, 횡단 관심사): 핵심 기능을 보조하기 위해 제공되는 기능이다. 예를 들어, 로깅, 보안 검사, 트랜잭션 관리 등이 부가기능에 해당한다.
핵심기능과-부가기능의-차이-및-횡단-관심사-구조도
핵심기능과-부가기능의-차이-및-횡단-관심사-구조도

이러한 부가기능들은 핵심 기능에만 쓰이지 않고, 여러 핵심 기능에 걸쳐서(Cross-Cutting) 등장한다는 특징이 있고, 이러한 특징 때문에 횡단 관심사라고도 불린다.

2. AOP는 어떻게 코드를 간결하게 만드는가?

AOP가 없는 상황을 가정해보자. 우리가 핵심 기능의 실행 시간을 측정해야 한다면, 각 핵심 기능마다 실행 시간 측정 코드를 삽입해야 한다. 예를 들어, 다음과 같이 말이다.

java
public void placeOrder() {
  long startTime = System.currentTimeMillis();

  // ... 핵심 기능 로직 ...

  long endTime = System.currentTimeMillis();
  System.out.println("Execution time: " + (endTime - startTime) + " ms");
}

문제는 이러한 코드가 OrderService 뿐만 아니라, PaymentService, MemberService 등 여러 클래스에 수십, 수백번 반복되서 똑같이 복사-붙여넣기 되어야 한다는 점이다. 이렇게 되면, 다음과 같은 문제가 발생한다.

  1. 코드 중복: 동일한 코드가 여기저기 흩어진다.
  2. 유지보수성 저하: 실행 시간 측정 로직을 변경해야 할 때, 모든 핵심 기능에 일일이 수정해야 한다. 예를들어, ms 단위를 ns 단위로 바꾸고 싶다면, 모든 메서드를 찾아서 수정해야 한다.
  3. 가독성 저하: 핵심 로직 사이에 부가 기능이 섞여 있어, 핵심 로직을 파악하기 어렵다.

3. OOP가 아닌, 굳이 AOP를 사용하는 이유

우리는 이 과정에서 다음과 같은 의문을 가질 수 있다.

"반복되는 코드? 그거 그냥 TimerUtils 같은 클래스로 만들어서 모듈화하면 되는 것 아니야? 그냥 OOP로도 충분히 해결할 수 있잖아?"

맞다. OOP로도 충분히 해결할 수 있다. TimerUtils 같은 유틸리티 클래스를 만들어서, 핵심 기능에서 호출하는 방식으로 말이다. 하지만, 이 방법과 AOP에는 결정적인 차이가 있다.

  • OOP 모듈화 (Explicit Call): 내가 만든 핵심 로직 안에서 TimerUtilsimport하고, 직접 명시적으로 호출해야 한다. 즉, 내 핵심 로직 코드가 부가기능에 대해 알고 있어야 한다. 이는 다르게 말해, 핵심 로직이 부가기능에 의존한다는 의미이다.
  • AOP (Automatic Injection): 핵심 로직은 Timer의 존재조차 모른다. 나는 단지 "주문 서비스 로직 실행 전후에 이 코드를 넣어줘"라고 선언만 할 뿐이다. 그러면 AOP 프레임워크가 알아서 핵심 로직에 부가기능 코드를 자동으로 삽입해준다. 즉, 핵심 로직은 부가기능에 대해 전혀 알지 못하며, 의존하지도 않는다. 이를 Weaving 이라고 부른다.
구분OOP 모듈화AOP
방식명시적 호출 (Explicit Call)선언적 적용 & 자동 위빙 (Weaving)
의존성핵심 기능 -> 부가 기능의존성 없음 (서로를 모름)
코드 변경부가 기능 추가 시, 핵심 기능 코드 수정 필요부가 기능 추가 시, 핵심 기능 코드 수정 불필요

이 차이점이 중요한 이유는, AOP가 비즈니스 로직에 단 한줄의 부가 기능 코드도 남기지 않게 하는, 비침투적인(Non-Intrusive) 기술이기 때문이다.

이는 즉, 부가기능을 추가하거나 변경하더라도 핵심 로직 코드를 수정할 필요가 없고, 반대로 핵심 로직을 변경하더라도 부가기능 코드를 수정할 필요가 없다는 뜻이다. 결과적으로 AOP는 이를 통해 유지보수성과 확장성을 크게 향상시킨다.

4. Aspect(관점)란 무엇인가?

그렇다면, AOP에서 말하는, 코드를 분리하는 기준이 되는 'Aspect(관점)'란 무엇일까? 이는 프로그램을 바라보는 시각(Viewpoint)를 바꾸는 것이라고 할 수 있다.

  • 기능(OOP)의 관점: "이 객체는 무슨 일을 하는가?" (e.g., 주문 처리, 결제 처리, 회원 관리...)
  • 횡단 관심사(AOP)의 관점: "이 로직은 전체 시스템 중 어디에 흩뿌려져 있는가?" (e.g., 로그를 찍어야 하는 지점들, 트랜잭션이 필요한 지점들...)

마치 건물을 지을 때 '평면도(비즈니스 로직)' 만 보는 것이 아니라, '전기 배선도(횡단 관심사)', '수도 배관도(횡단 관심사)' 등을 따로 떼어내어 관리하는 것과 같다. 이 각각의 배선도와 배관도가 바로 Aspect다.

5. 포함 관계로 이해하기 (Aspect > Advice > Pointcut)

이 관점(Aspect)은 추상적인 개념이 아니다. 코드 상에서 Aspect는 다음 두 가지를 포함하는 구체적인 모듈이다.

Note
Aspect = Advice(할 일) + Pointcut(적용 지점)
Aspect-Advice-Pointcut-포함-관계-다이어그램
Aspect-Advice-Pointcut-포함-관계-다이어그램
  1. Aspect (관점): "보안", "로깅" 같은 가장 큰 카테고리
  2. Advice (할 일): 관점 안에 포함된 실제로 해야 할 일(행동)
  • "무엇을? (로그를 남긴다)"
  • "언제? (메서드 실행 전후)"
  1. Pointcut (적용 지점): Advice가 적용될 구체적인 위치(메서드 등)
  • "이 부가 기능을 사용하는 대상 핵심 로직은 누구인가? (OrderService.placeOrder())"
  1. Joinpoint (결합 지점): 실제로 핵심 로직이 실행되는 특정 시점(메서드 호출 등)

즉, 하나의 Aspect는 "어디에(Pointcut) 무엇을(Advice) 할 것인가?" 에 대한 정의를 모두 품고 있는 모듈인 것이다.

6. 정리하기

이제 이해한 내용을 바탕으로 AOP를 한 줄로 요약하면 다음과 같다.

Note
"애플리케이션 전체에 흩어진 공통 기능(Advice)을, 어디에 적용할지(Pointcut) 정의하여, 핵심 비즈니스 로직의 수정 없이(Weaving) 하나의 독립적인 모듈(Aspect)로 관리하는 기법"

OOP가 기능(Feature) 중심의 수직적 분리라면, AOP는 관점(Aspect) 중심의 수평적 분리이다.

7. 코드로 개선하기

마지막으로, 앞서 예시로 든 실행 시간 측정 코드를 AOP로 개선한 예시를 통해 정리해보자.

AOP 적용 전

java
public void placeOrder() {
  long startTime = System.currentTimeMillis();

  // ... 핵심 기능 로직 ...

  long endTime = System.currentTimeMillis();
  System.out.println("Execution time: " + (endTime - startTime) + " ms");
}

AOP 적용 후 - 핵심 로직

java
@Service
public class OrderService {
    public void placeOrder() {
        // 부가 기능 코드는 모두 사라지고, 핵심 비즈니스 로직만 남는다.
        System.out.println("주문 로직 수행...");
    }
}

AOP 적용 후 - Aspect 코드

java
@Aspect
@Component
public class PerformanceAspect {
  // Pointcut: 어디에? (com.example 패키지 내 모든 메서드)
  // Advice: 무엇을? (실행 시간 측정)
  @Around("execution(* com.example..*(..))")
  public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    long start = System.currentTimeMillis();

    Object proceed = joinPoint.proceed(); // 핵심 기능 실행(Joinpoint)

    long executionTime = System.currentTimeMillis() - start;
    System.out.println(joinPoint.getSignature() + " executed in " + executionTime + " ms");
    return proceed;
  }
}

이제 우리는 핵심 로직을 수정하지 않고도, PerformanceAspect의 설정만으로 시스템 전체의 실행 시간 측정을 적용할 수 있다. 이를 응용하면 로깅, 보안 검사, 트랜잭션 관리 등 다양한 횡단 관심사를 효과적으로 처리할 수 있을 것이다. 이것이 바로 AOP의 강력한 힘이다.

8. 참고 자료

BlueNyang
작성자BlueNyang
라이선스
CC BY NC
BlueNyang

BlueNyang

BlueNyang의 개발 log

카테고리

  • Development
  • Framework
  • Language
  • Dev Tools
  • DevOps & Infra
  • Studies

페이지

© 2026 BlueNyang. All rights reserved.

Made with Nuxt.js and Directus