ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring AOP란 무엇인가?
    Java 2023. 11. 30. 22:24

    개요

    @Transactional을 정리하면서 AOP에 관한 내용이 많이 나왔는데, AOP를 따로 정리한 적이 없기 때문에 이번에 정리를 해보려고 한다.

    AOP란?

    AOP는 Aspect-Oriented Programming의 약자로 관점 지향 프로그래밍이라 불린다.

    어떤 로직을 기준으로 핵심적인 관점과 부가적인 관점으로 나눠보고 그 관점을 기준으로 각각 모듈화 하겠다는 의미

    주로 핵심 비즈니스 로직에서 횡단 관심사(Cross-cutting concerns)를 모듈화하고 분리하기 위한 목적으로 사용된다.

    AOP는 횡단 관심사를 별도의 모듈로 분리하여 개발자가 핵심 비즈니스 로직에 집중할 수 있도록 해준다.

    위의 사진과 같이 흩어진 관심사, 횡단 관심사의 모듈화를 통해 핵심 비즈니스 로직을 분리한다.


    관점 지향 프로그래밍 : 소프트웨어 개발에서 횡단 관심사(Cross-cutting concerns)를 모듈화하고 분리하는 프로그래밍 패러다임 중 하나이다.

    횡단 관심사 : 어플리케이션의 여러 부분에 걸쳐 나타나는 공통적인 로직이나 기능을 말한다.

    실행시간 측정, 로깅, 보안, 트랜잭션 관리, 예외 처리 등이 해당된다.

    AOP 주요 용어 및 개념

    용어 개념
    Aspect AOP에서는 모듈화되는 각 관심사(부가적인 기능)를 "Aspect"로 정의한다.
    Aspect는 Advice와 Pointcut을 포함한다.
    Advice Aspect에서 특정 Join Point에 실행되는 코드 블록
    Aspect의 기능을 정의한 것으로 타겟의 실행 전, 후, 예외 발생 시 등에 실행되는 코드(부가적인 기능)를 의미
    Target Aspect가 적용될 곳 (Class, Method..etc)
    Pointcut Advice가 적용될 Join Point를 선택하는 규칙을 정의한다.
    메서드 호출, 패키지 경로, 특정 어노테이션 등으로 포인트컷을 지정할 수 있다.
    즉, Join Point의 상세 스펙을 정의한 것
    Join Point 어플리케이션 실행 중 특정 지점을 나타낸다.
    메서드 호출, 예외 발생 등이 조인 포인트에 해당한다.
    Weaving Spring AOP는 컴파일 타임이나 런타임에 Aspect를 적용하는 방식을 사용한다.
    스프링 IoC컨테이너가 빈을 생성하면서 Aspect를 적용하는데 이를 위빙이라고 한다.

     

    어노테이션 설명
    @Aspect 해당 클래스를 Aspect로 사용하겠다는 것을 명시
    @Before 대상 “메서드”가 실행되기 전에 Advice를 실행
    @AfterReturning 대상 “메서드”가 정상적으로 실행되고 반환된 후에 Advice를 실행
    @AfterThrowing 대상 “메서드에서 예외가 발생”했을 때 Advice를 실행
    @After 대상 “메서드”가 실행된 후에 Advice를 실행
    @Around 대상 “메서드” 실행 전, 후 또는 예외 발생 시에 Advice를 실행

    Spring AOP의 advice실행시점(Join Point)는 메서드 레벨만 지원한다.

     

    사용예시

    @Aspect
    public class LoggingAspect {
    
        @Before("execution(* com.example.service.*.*(..))")
        public void beforeServiceMethod(JoinPoint joinPoint) {
            // 메서드 호출 전에 실행되는 코드
            System.out.println("Before method: " + joinPoint.getSignature().getName());
        }
    
        @AfterReturning(
            pointcut = "execution(* com.example.service.*.*(..))",
            returning = "result"
        )
        public void afterReturningServiceMethod(JoinPoint joinPoint, Object result) {
            // 메서드가 예외 없이 정상적으로 종료된 경우에 실행되는 코드
            System.out.println("After returning from method: " + joinPoint.getSignature().getName());
            System.out.println("Result: " + result);
        }
    }

    위의 예시에서 @Aspect 어노테이션은 해당 클래스가 Aspect임을 나타내며,

    @Before @AfterReturning 어노테이션은 각각 메서드 호출 전과 메서드 호출 후에 실행될 Advice를 정의하고 있다. 

    execution을 사용한 포인트컷은 com.example.service 패키지의 모든 메서드 호출을 대상으로 한다.

    AOP 원리

    프록시는 타겟을 감싸서 요청을 대신 받아주는 Wrapping 오브젝트이다. 클라이언트가 타겟을 호출하게 되면, IoC컨테이너에 의해 프록시 빈을 생성하게 된다. 동적으로 생성된 프록시 빈은 타겟의 메서드가 호출되는 시점에 부가기능을 추가할 메서드를 자체적으로 판단하고 가로채어 부가기능을 주입해주는데, 이것을 런타임 위빙(RuntimeWeaving)이라 한다.

     

    IoC(Inversion of Control) 컨테이너 : 객체의 생명주기와 의존성관리를 중앙에서 관리하는 컨테이너이다.

    프레임워크나 컨테이너 내부에서 객체의 생성, 초기화, 관리, 소멸 등을 담당하여 개발자는 이러한 작업들을 직접 수행하지 않고도 객체를 사용할 수 있도록한다.

    Spring에서는 자체 검증 로직에 따라 인터페이스 유무를 판단하고, 이에 따라 JDK DynamicProxy나 CGLIB방식으로 프록시를 자동 생성해 준다.

     

    프록시를 만드는 두 가지 방법 

    • JDK DynamicProxy
      JDK Dynamic Proxy는 Java의 리플렉션 패키지에 존재하는 Proxy 클래스를 통해 생성된 프록시 객체를 의미한다.
      타겟의 인터페이스를 상속받아 구현한다. 리플렉션의 Proxy 클래스가 동적으로 프록시 객체를 생성해 주므로 JDK Dynamic Proxy라는 이름이 붙여졌다.
      리플렉션을 사용하기 때문에 성능이 조금 떨어지는 단점이 있다.

    타깃의 인터페이스를 구현하여 Proxy를 생성한다.

    타깃의 인터페이스를 자체적인 검증 로직을 통해 ProxyFactory에 의해 타깃의 인터페이스를 상속한 Proxy 객체 생성하고,

    Proxy 객체에 InvocationHandler를 포함시켜 하나의 객체로 반환

     

    • CGLib(Code Generator Library)
      CGLib은 Code Generator Library의 약자로, 클래스의 바이트코드를 조작하여 Proxy 객체를 생성해주는 라이브러리이다.

      타겟의 클래스를 상속해서 Proxy를 생성하기 때문에 타겟의 인터페이스가 없어도 생성된다.
      CGLib은 Enhancer라는 클래스를 통해 Proxy를 생성할 수 있다.
      리플랙션을 사용하지 않기때문에 성능적으로는 JDK DynamicProxy보다 뛰어나다.

    타겟의 클래스를 상속받아서 Proxy를 생성한다.

    CGLib은 타겟 클래스의 모든 메서드를 재정의해서 프록시를 생성한다.

    따라서 CGLib를 적용할 클래스는 final 메소드가 들어있거나, final 클래스면 안되며,  private 접근자로 된 메소드도 상속이 불가하므로 적용되지 않는다.

     

     

    주의점

    타겟 클래스안에서 내부 메서드를 직접 호출하게 될 경우, AOP가 정상적으로 동작하지 않는다.

    final class 처럼 상속이 불가능경우 proxy를 생성하지 못해서 정상동작하지 않는다.

     

     

     

     


    참고자료

    https://catsbi.oopy.io/fb62f86a-44d2-48e7-bb9d-8b937577c86c

     

    https://engkimbs.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81AOP

     

    https://adjh54.tistory.com/133#:~:text=%2D%20Spring%20AOP%EB%8A%94%20%EC%8A%A4%ED%94%84%EB%A7%81%20%ED%94%84%EB%A0%88%EC%9E%84,%ED%96%A5%EC%83%81%ED%95%98%EB%8A%94%EB%8D%B0%20%EB%8F%84%EC%9B%80%EC%9D%84%20%EC%A4%8D%EB%8B%88%EB%8B%A4.

     

    https://gmoon92.github.io/spring/aop/2019/04/20/jdk-dynamic-proxy-and-cglib.html

     

    https://steady-coding.tistory.com/608

Designed by Tistory.