[Spring 입문] 03. AOP(Aspect Oriented Programming)

👐

안녕하세요.
이번 글에서는 관점 지향 프로그래밍을 의미하는 AOP에 대해 알아보겠습니다.

  1. AOP(Aspect Oriented Programming)이란?
    : AOP, 관점 지향 프로그램이란, 횡단 관심사(흩어진 관심사, cross-cutting concern)의 분리를 허용함으로써 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임입니다.

  • 그렇다면 횡단 관심사란 무엇인가요?
    : 이를 이해하기 위해 샘플 메서드를 보겠습니다.
public void A() {
    System.out.println("hello");
    methodA();
    System.out.println("bye");
}

public void B() {
    System.out.println("hello");
    methodB();
    System.out.println("bye");
}

두 개의 메서드는 hello, bye 출력이라는 동일한 코드를 가지고 있습니다. 유사한 메서드가 더 많이 만들어지고 코드를 수정해야하는 경우가 생긴다면, 코드를 유지관리하기 매우 비효율적일 것입니다.

이렇게 핵심적인 기능이 아닌 중간마다 사용되어 삽입되어야 할 기능들에 대한 관심사들을 횡단관심사(Cross-Cutting Concerns)라고 합니다.
예를 들어 로깅, 보안, 트랜잭션 처리 등 비즈니스 핵심 사항이 아닌 다양한 횡단관심사가 존재할 수 있습니다.

  • 다시 AOP란?
    : 즉, AOP란 소스코드 상에서 각 관점을 핵심 관점(business logic)과 부가적인 관점(횡단관심사)로 나누어보고 관점을 각각 분리하는 것입니다.
    다음과 같은 경우에 자주 활용합니다.

    • 모든 log문 통합 관리
    • timer 확인 (server 및 DB 활용 예상 시간과 실제 걸린 시간에 대해 알기 위해)
    • 값 변환


2. AOP 주요 개념

  • Aspect : 횡단 관심사를 모듈화한 것을 의미하며, Advicd와 PointCut을 합친 개념
  • Advice : 각 관심사가 하는 실제 부가기능을 담은 구현체
  • JoinPoint : Advice를 적용 가능한 지점
  • PointCut : JointPoint의 부분 집합으로 실제 Advice가 적용되는 JoinPoint를 의미
  • Target : Aspect를 적용하는 곳

3. 주요 Annotation
  • @Aspect : 자바에서 널리 사용하는 AOP 프레임워크에 포함되며, AOP를 정의하는 Class에 할당
  • @PointCut : 기능을 어디에 적용시킬지, 메서드? Annotation? 등 AOP를 적용시킬 지점을 설정
  • @Before : 메서드 실행 이전 AOP 적용
  • @After : 메서드가 성공적으로 실행 후 AOP 적용 (예외가 발생하더라도 실행)
  • @AfterReturning : 메서드 호출 성공 실행 시 AOP 적용 (Not Throws)
  • @AfterThrowing : 메서드 호출 실패 예외 발생 시 AOP 적용 (Throws)
  • @Around : Before / After / 예외 발생 시 모두 AOP 적용 가능하도록 제어


4. 예제 (in Spring Framework)

1) AOP 적용 이전

  • business logic 이 아닌 println 출력 코드가 연속적으로 존재하고 있습니다.
    -> 이후 유지 보수에 비효율적
package com.example.aop.controller;

import com.example.aop.dto.User;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class RestApiController {

    @GetMapping("/get/{id}")
    public String get(@PathVariable Long id, @RequestParam String name) {
        System.out.println("get method");
        System.out.println("get method : " + id);
        System.out.println("get method : " + name);
        return id + " " + name;
    }
}
  • 출력 결과


2) AOP 적용

  • 중복되는 코드를 효율적으로 관리할 수 있습니다.
package com.example.aop.controller;

import com.example.aop.dto.User;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class RestApiController {

    @GetMapping("/get/{id}")
    public String get(@PathVariable Long id, @RequestParam String name) {
        return id + " " + name;
    }
}

package com.example.aop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect // aop 로 동작하기 위함 (class 에 설정)
@Component // [DI] Spring 에서 관리한다.
public class ParameterAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))") // 메서드에 설정
    private void cut() {

    }

    @Before("cut()") // cut()이라는 Pointcut 실행되기 전에 메서드를 실행
    public void before(JoinPoint joinPoint) {
        // methodSignature 객체를 통해 method 이름을 알 수 있다
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        System.out.println(method.getName());

        Object[] args = joinPoint.getArgs();

        for(Object obj : args) {
            System.out.println("type: " + obj.getClass().getSimpleName());
            System.out.println("value : " + obj);
        }
    }

    @AfterReturning(value = "cut()", returning = "returnObj")
    public void afterReturn(JoinPoint joinPoint, Object returnObj) {
        System.out.println("return obj");
        System.out.println(returnObj);

    }
}

  • 출력 결과

이번 글에서는 관점 지향 프로그래밍을 의미하는 AOP에 대해 알아보았습니다.

끝!🐶

감사합니다~

좋은 웹페이지 즐겨찾기