본문 바로가기
스프링

자바 스프링의 AOP구현에 사용되는 도구 2가지

by 흰색남자 2023. 3. 19.

0. AOP란?

개발을 하다보면 공통 로직이 생길 수 밖에 없다. 예를들면 예외처리, 시간 측정 등이 해당된다. 이러한 공통 로직을 줄이고 핵심 로직을 부각시키기 위한 것이 AOP의 특징이다.

1. 포스팅의 목표

AOP구현에 사용되는 도구를 알아보고 적재 적소에 잘 활용할 수 있어지는 것이 이번 포스팅의 목표이다.

2. 사전 용어 정리

  1. Aspect : 여러 객체에 공통적으로 적용되는 로직
  2. Joinpoint : 프로그램이 실행 중 발생하는 메서드, 생성자, 필드 값 변경 등을 가르키는 특수한 지점
  3. Advice : 특정 Joinpoint의 Aspect에 의한 동작. 대상 객체의 Joinpoint에 Weaving되어 동작할 수 있는 코드.
  4. Weaving : Aspect 클래스에 정의 한 Advice 로직을 타깃에 적용하는 것을 의미. Advice를 비즈니스 로직 코드에 삽입하는 것.
  5. Pointcut : Joinpoint의 정규 표현식. Joinpoint가 Pointcut에 일치할 때마다 해당 Pointcut에 관련된 Advice로직이 수행됨

3. AOP를 구현하는 2가지 방법

이러한 AOP를 구현하는 방법에는 2가지가 있다.

3-1 Spring AOP.

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

스프링의 AOP를 이용하면 컨트롤러에 대한 예외처리, 시간 측정 등 공통 로직 처리를 쉽게 구현할 수 있다.

아래는 스프링 AOP를 사용하여 예외처리 핸들러를 구현한 것이다.
구현에 앞서 ResponseEntity와 ErrorCode 객체를 만들고, Exception을 상속받아 커스터마이징된 예외를 만들어주었다.

3-2-1 Spring AOP의 Advice를 활용한 예외처리 핸들러 구현

@Slf4j
@RestControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {


    @ExceptionHandler(IdAlreadyExistException.class)
    public ResponseEntity<BaseResponse> handleIdAlreadyExist() {
        log.info(ErrorCode.IdAlreadyExist.getMessage());
        return ResponseEntity.badRequest().body(new BaseResponse(ErrorCode.IdAlreadyExist));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<BaseResponse> handleNotValid(MethodArgumentNotValidException exception) {
        String validateMsg = exception.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        log.info(validateMsg);
        return ResponseEntity.badRequest().body(new BaseResponse(4001, validateMsg));
    }

}

3-2 Aspectj

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

Aspectj 를 사용하는 것과 Spring AOP를 사용하는 객체에 대한 패키지부터 다르다.

3-2-1 Aspectj 예외처리 핸들러 구현

Aspectj를 사용해서 컨트롤러에 대한 예외처리를 구현한 예제이다.

@Aspect
@Component
public class ExceptionControllerHandler {

    @Pointcut("execution(* com.example.demo.*Controller.*(..))")
    private void cut() {
    }

    @Around("cut()")
    public Object exceptionAop(ProceedingJoinPoint pjp) {
        System.out.println("start");
        Object proceed = null;
        try {
            proceed = pjp.proceed();

        } catch (FirstException e) {
            System.out.println("f1");
            return ResponseEntity.status(400).body("f1 error");
        } catch (SecondException e) {
            System.out.println("f2");
            return ResponseEntity.status(400).body("f2 error");
        } catch (Throwable e) {
            return ResponseEntity.status(400).body("runtime error");
        }
        return proceed;
    }

위 코드를 자세히 보면, Pointcut을 활용하여 컨트롤러 뿐 아니라, 범위를 자유롭게 지정하여 다른 패키지, 객체에 적용 가능한 것을 볼 수 있다.
이는 곧 유연한 확장성과 범용성을 의미한다.

4. Aspectj와 Spring AOP 비교

  1. 동작방식
    ```
    컴파일 시점 Weaving : AspectJ 컴파일러가 Aspect 코드와 애플리케이션의 소스 모두 입력받아 Weaving된 class 파일을 생성함
    컴파일 후 Weaving : 바이너리 Weaving으로도 알려져 있습니다. 이미 존재하는 class 파일과 jar 파일을 Weaving하기 위해 사용됨
    로드 시점 Weaving : 위 바이너리 Weaving과 유사하나 Weaving 시점이 class 파일이 JVM에 로드될때 까지 연기된다는 점이 다름
    ```
  2. 동작 방식
    ```
    Spring AOP
    - DK 동적 Proxy : Spring AOP에서 선호되는 방식입니다. 언제든지 대상 객체가 한 개의 인터페이스를 구현하면 JDK 동적 프록시를 사용할 수 있음
    - CGLIB Proxy : 대상 객체가 인터페이스를 구현하지 않는 경우 CGLIB 프록시를 사용할 수 있음.

    Aspectj
    클래스들이 Aspect와 함께 바로 컴파일되기 때문에 런타임시에는 아무것도 하지 않음.
    ```
  3. 한계

4.성능

- Spring AOP
애플리케이션의 시작시에 생성된 Proxy들을 기반으로한 프레임워크이고, 성능에 악영향을 주는 훨씬 적은 수의 메서드만을 지원함.

- AspectJ
Aspect를 애플리케이션이 실행되기 전에 Weaving 하기 때문에 Spring AOP와는 달리 런타임시 과부하가 없음

- 결론
컴파일 시점 Weaving은 런타임 Weaving에 비해 훨씬 빠름.
AspectJ가 Spring AOP보다 8배에서 35배 가까이 빠름.

 

-- 추가 보충 자료.

Aspectj는 어떻게 컴파일 시점에 Weaving이 이루어질까?

Aspectj 컴파일러
개발자가 AspectJ 코드를 JVM(Java Virtual Machine)에서 실행할 수 있는 바이트코드로 컴파일할 수 있게 해주는 도구

동작 순서
aspectj 코딩 > aspectj 컴파일러 동작 > 자바 코드에 aspectj 컴파일러가 바이트화한 코드를 삽입함. > JVM에 의해 실행

AspectJ 컴파일러와 바이트코드는 개발자가 모듈식 및 재사용 가능한 방식으로 횡단 문제를 구현하여 대규모 Java 애플리케이션을 보다 쉽게 ​​개발하고 유지 관리할 수 있도록 하는 강력한 도구임.

 

Pointcut 작성 규칙

 

https://wpunch2000.tistory.com/22

 

[Spring] 스프링 AOP Pointcut 표현식

포인트컷을 이용하면 어드바이스 메소드가 적용될 비즈니스 메소드를 정확하게 필터링 할 수 있음 ( ※ Pointcut : 특정 조건에 의해 필터링된 Joinpoint, 수많은 Joinpoint 중에 특정 메서드에서만 공통

wpunch2000.tistory.com

https://sjh836.tistory.com/157

 

Spring AOP (개념, 용어, 원리, 포인트컷 표현식, JoinPoint API)

1. AOP란?Aspect Oriented Programming 의 약자로 관점지향 프로그래밍이라고 부른다. IoC가 낮은 결합도와 관련된 것이라면 AOP 는 높은 응집도와 관련되어 있다.서비스들의 비즈니스 메소드들은 복잡한

sjh836.tistory.com

http://closer27.github.io/backend/2017/08/03/spring-aop/

 

Spring AOP · 어느 개발자의 한적한 공간

Spring AOP 2017.08.03 Day 2 - 스프링 AOP(Aspect Oriented Programming) 개요 낮은 결합도 높은 응집도는 기본, DI는 낮은 결합도를 위한 것이라면 AOP는 높은 응집도를 위한 것 엔터프라이즈 애플리케이션들은 보

closer27.github.io

https://heidish.tistory.com/70

 

'스프링' 카테고리의 다른 글

[JAVA, Spring ] equals, hashcode  (0) 2023.06.12
Tomcat과 Netty  (0) 2023.02.28
JPA, Hibernate, Spring Data JPA  (0) 2023.01.26