[Spring Boot] AOP

SeongWon Oh·2021년 8월 25일
0

Spring Framework

목록 보기
9/33
post-thumbnail

AOP란?

AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍을 의미한다.
관점 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 보고 관점을 기준으로 모듈화를 한다는 것을 의미한다.

객체지향 프로그래밍은 클래스가 단일 책임을 갖도록 분리하여 모듈들의 결합도는 낮고 응집도는 높아지게 설계를 한다. 객체지향 설계를 하면 하나의 모듈을 변경하였을 때 다른 모듈, 즉 시스템 전체에 주는 영향이 적어 유지보수가 쉽다는 장점이 있습니다. 하지만 이러한 설계를 하더라도 클래스의 로깅, 보안, 트렌잭션 처리 등 공통된 기능들이 흩어져서 존재한다는 아쉬움이 남는다.

이렇게 소스코드상에서 여러 부분에 반복해서 쓰이는 코드를 흩어진 관심사 (Crosscutting Concerns)라고 하며 흩어진 관심사를 관점에 따라 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하도록 하는 것이 AOP의 취지이다.
즉, OOP로 독립적으로 분리하기 어려운 부가기능들을 관점에 따라 모듈화하는 방식이다.


AOP관련 용어 정리

  • Business Object : 평범한 비즈니스 로직을 갖고 있는 클래스로 Spring annotation이 붙지 않은 보통 class이다.
  • Aspect : 흩어진 관심사를 모듈화 한 것으로 주로 부가기능들을 모듈화한다.
  • Target : Aspect를 적용하는 곳으로 class, method등이 있다.
  • Advice :
    • 특정한 JointPoint에서 aspect로 인해 실행될 액션으로 실질적인 부가기능을 담은 구현체이다.
    • Around-> Before-> AfterReturning, AfterThrowing-> After-> Around순으로 실행이 된다.
  • JointPoint : 프로그램 실행 중 Aspect가 발생하는 포인트들로 method실행 혹은 예외 시점을 의미한다. (Spring AOP에서는 method의 실행하는 포인트)
  • PointCut : JointPoint에 Aspect로 인해 적용될 Advice를 매칭시켜주는 속성으로 포인트식 표현식을 통해 Aspect가 적용될 JointPoint를 필터링한다.

Spring boot에서 AOP사용 준비하기

spring boot에서 AOP를 사용하기 위해서는 dependency를 추가해줘야한다.
우선 build.gradle의 dependencies부분에 아래의 코드를 추가해보자

implementation 'org.springframework.boot:spring-boot-starter-aop'

AOP를 사용 예시

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

    @GetMapping("/get/{id}")
    public void get(@PathVariable Long id, @RequestParam String name){
        System.out.println("Get method");
        System.out.println("Get method : "+id);
        System.out.println("Get method : "+name);
    }

    @PostMapping("/post")
    public void post(@RequestBody User user){
        System.out.println("Post method : "+user);
    }
}

위의 코드를 보면 2개의 method가 존재하지만 실제 서비스를 운영하면 많은 method들이 존재할 것이다. 이러한 method의 출력을 log로 한곳에 모을 수 있다.

ParameterAop.java

package com.example.aop.aop;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class ParameterAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))")
    private void cut() {

    }

    @Before("cut()")
    public void before(JoinPoint joinPoint) {
	// Joinpoint는 들어가는 지점에 대한 정보를 갖을 수 있는 객체이다.

        // 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("type : "+ obj);
        }
    }
    
    // returning에는 내가 받고싶은 객체의 이름을 넣어준다. (이는 method의 parameter명과 동일해야한다.)
    @AfterReturning(value = "cut()", returning = "returnObj")
    public void afterReturn(JoinPoint joinPoint, Object returnObj) {
        System.out.println("Return obj");
        System.out.println(returnObj);
    }

}

AOP를 생성하는 방법은 다음과 같다. 먼저 해당 class를 AOP로 동작하게 하기 위해 class위에 @Aspect를 추가해줘야한다. 또한 해당 class를 Spring Bean에 등록하여 Spring이 관리하게 하기 위해 @Component도 붙여줘야한다.

class정의에서 내려가 @Pointcut부분을 보도록 하자, 앞서 말했듯이 PointCut은 JointPoint에 Aspect로 인해 적용될 Advice를 매칭시켜주는 일을 수행한다. 나는 com.example.aop.controller하위에 있는 모든 것에 AOP를 동작하게 하기위해 아래와 같이 작성하였다.

@Pointcut("execution(* com.example.aop.controller..*.*(..))")

다음으로 @Before부분을 보도록 하자.
@Before는 특정 JointPoint에서 aspect로 인해 실행 될 액션을 담고 있는 Advice라는 것을 알리는 annotation이며 @Before이외에도 @Around, @AfterReturning, @AfterThrowing, @After가 존재한다.
@Before("cut()")의 경우는 cut method가 실행되기 전에 해당 method를 실행시키겠다는 의미를 내포한다.
그 외에도 하단에 위치한 @AfterReturning(value = "cut()", returning = "returnObj")은 Cut이후 Return을 할 때 returnObj를 return하겠다는 의미를 가진다.


Reference

profile
블로그 이전했습니다. -> https://seongwon.dev/

0개의 댓글