Spring AOP에 대해서

3339 단어 SpringSpring

AOP란?

Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 어떤 로직을 기준으로 핵심 비즈니스 기능, 공통 기능(부수 기능)으로 구분하고 공통 기능을 기준으로 각각 모듈화하는 방법이다.
(모듈화: 공통된 로직이나 기능을 하나의 단위로 묶는 것)

AOP를 사용하는 이유

공통적인 기능이 있는 경우 매번 상속을 받아 공통 기능을 구현하기에는 한계가 있다. 예를들어, API 호출 시 호출 성공 여부를 로그에 남기는 로직을 만들고자 할 때 AOP를 사용하지 않는다면 모든 API마다 호출 성공 여부를 로그에 남기는 반복적인 작업을 해야한다. 결국 중복코드가 생길 것이고 코드의 변경이 생기면 여러 코드에 종속적으로 변경이 필요하고 핵심 비즈니스 기능에 부수적인 기능이 추가되어 가독성과 효율성이 떨어지게 된다.
이러한 것을 보완하기 위해 AOP를 사용하고 공통 관심 사항을 핵심 비즈니스 로직과 분리하여 핵심 로직을 깔끔하게 유지할 수 있다. 만약 공통 모듈의 수정사항이 생기면 다른 모듈의 수정 없이 공통 모듈만 수정하면 된다.

AOP Aspectj를 구현하기 위해 사용되는 어노테이션

  • @Pointcut: aspectJ를 적용할 타겟을 정의한다. 전체 컨트롤러의 메서드가 대상이고, 특정 어노테이션이나 특정 메서드에 적용하길 원하면 범위를 정의할 수 있다.
  • @Before: aspectJ를 적용할 타겟 메서드가 실행하기 전에 수행된다.
  • @AfterReturning: aspectJ를 적용할 타겟 메서드가 실행된 후에 수행된다. (제일 마지막에 수행)
  • @Around: aspectJ를 적용할 타겟 메서드 실행 전, 후 처리를 모두 할 수 있다.

AOP 적용해보기

다음 코드는 https://vmpo.tistory.com/100 이 블로그에 있는 코드를 토대로 작성하였다.
@GetMapping 어노테이션이 설정된 메서드나 클래스에 대해 GetMapping 이라는 이름의 메서드를 실행 시 공통 로직이 수행된다.

@Aspect
@Component
@Log4j2
public class AopExample {
    private static final Logger LOGGER = LoggerFactory.getLogger(AopExample.class);

    // @GetMapping 설정된 메서드 또는 클래스를 설정한다.
    // GetMapping이 설정된 특정 클래스/메서드에서만 Aspectj가 적용되도록 한다.
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void GetMapping() {}

    // aspectJ를 적용할 타겟 메서드가 실행하기 전에 수행된다.
    @Before("GetMapping()")
    public void before(JoinPoint joinPoint) {
        LOGGER.info("============== AOP Aspectj test : before logging start ============");
        LOGGER.info("============== AOP Aspectj test : before logging end ============");
    }

    // aspectJ를 적용할 타겟 메서드가 실행된 후에 수행된다. (제일 마지막에 수행)
    @AfterReturning(pointcut = "GetMapping()", returning = "result")
    public void AfterReturning(JoinPoint joinPoint, Object result) {
        LOGGER.info("============== Aspectj test : AfterReturning logging start ===============");
        LOGGER.info("============== Aspectj test : AfterReturning logging end ==============");

    }

    // aspectJ를 적용할 타겟 메서드 실행 전, 후 처리를 모두 할 수 있다.
    @Around("GetMapping()")
    public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.info("============== Aspectj test : Around logging start =================");
        try{
            Object result = proceedingJoinPoint.proceed();
            LOGGER.info("================ Aspectj test : Aroung logging end ==============");
            return result;
        }catch(Exception e){
            LOGGER.error("=============== Aspectj Around Exception ==================");
            LOGGER.error(e.toString());
            return null;
        }
    }

}

@Around는 Object result = proceedingJoinPoint.proceed(); 이 작업 전에 시작하고
proceed() 작업이 완료되고 종료된다.
@Around 시작 -> @Before 시작, 종료 -> @Around 종료 -> @AfterReturning 시작, 종료

*참고 자료
https://mangkyu.tistory.com/121
https://vmpo.tistory.com/100

좋은 웹페이지 즐겨찾기