스프링

AOP(Aspect Oriented Programming)

꾸진 2022. 5. 23. 23:50

AOP란?

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

 

관점 지향이라고 하니 의미가 크게 와닿지 않을 수 있는데요,  

 

기능을 핵심 비즈니스 기능공통기능으로 구분하고, 모든 비즈니스 로직에 들어가는 공통기능의 코드를 개발자의 코드 밖에서 필요한 시점에 적용하는 프로그래밍 방식이라고 볼 수 있습니다.

 

아래의 예시 코드를 통해 더 자세히 알아보겠습니다.

@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;
    
    public long join(UsercreateRequest userCreateRequest) {
    	//트랜잭션 begin
        //로깅
        //비즈니스 로직
        //트랜잭션 commit
    }

}

 

위와 같이 사용자를 관리하기 위한 UserService가 존재한다고 했을 때, 회원가입 메소드로 join을 구현한다고 가정하겠습니다.

 

해당 메소드를 구현할 때 비즈니스 로직 이외에 트랜잭션, 로깅 등을 포함하게 되는데

이는 비즈니스 로직보다는 부가 기능에 가깝다고 볼 수 있습니다.

 

핵심 비즈니스 로직을 담고 있지는 않지만 애플리케이션에 부가됨으로써 의미를 갖는 특별한 모듈입니다.

 

만약 join이라는 메소드 이외에 다른 메소드에서도 트랜잭션, 로깅 처리 등을 반복적으로 사용하게 된다면

이를 공통적으로 처리해줄 수 있는 무언가가 있으면 좋지 않을까요?

 

AOP가 바로 그 역할을 해주게 됩니다.

 

트랜잭션, 로깅, 메소드 실행 시간 체크 등 부가 기능을 모듈화하고 핵심 비즈니스 로직에서 분리해 재사용하는 것이 AOP의 취지라고 볼 수 있습니다. 

 

(이러한 부가 기능을 횡단 관심사(Cross-cutting concerns)라고 부르기도 합니다.)

AOP를 사용하게 되면 중복되는 코드 제거, 효율적인 유지보수, 높은 생산성 등의 장점이 있게 되는 것이죠.

 

(AOP는 OOP와 같은 일종의 패러다임이기 때문에 각 언어마다 AOP에 대한 구현체가 있습니다.)

 

AOP에서 등장하는 용어는 다음과 같습니다.

 

AOP의 용어

  • Target: 어떤 대상에 부가 기능을 부여할 것인가
  • Advice: 어떤 부가 기능인지? Before, AfterReturning, AfterThrowing, After, Around
  • Join point: 어디에 적용할 것인가? 메소드, 필드, 객체, 등
  • Point cut: advice가 적용될 지점, Spring AOP에서는 advice가 적용될 메소드를 선정

(Spring AOP는 메소드 조인 포인트만 지원합니다)

 

Spring에서의 AOP 사용 예시

아래의 예제와 함께 Spring에서 AOP를 어떻게 적용하는지 보겠습니다. 

@Slf4j
@Aspect
@Component
public class LoggingAspect {

    @Pointcut("within(com.prgrms.domain.user.service.UserService)")
    private void advicePoint() {
    }
    
    @Around("advicePoint()")
    public void loggingAround(ProceedingJoinPoint joinPoint) throws Throwable {
    	MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        
    	log.info("Before call method: {}", methodSignature.getName());
        
        Object result = joinPoint.proceed(); // 타겟 메소드 실행
        
        log.info("After call method: {}", methodSignature.getName());
    
    }

}

위는 예시로 봤던 UserSerivce 클래스 내 모든 메소드에 로깅 AOP를 적용한 예제 코드입니다.

 

@PointCut 어노테이션을 통해 AOP를 적용될 대상을 정의해줍니다.

현재 com.prgrms.domain.user.service 패키지 내 UserService 내 모든 메소드에 적용하도록 명시해줬습니다.

 

@Around 어노테이션을 통해 타겟 메소드의 실행 전과 후에 AOP를 적용하도록 해줬습니다.

 

Advice 설정은 5가지로 정의할 수 있습니다.

 

  • @Around: 타겟 메소드 실행 전과 후
  • @Before: 타겟 메소드 실행 전
  • @After: 타겟 메소드 실행 후
  • @AfterReturning: 타겟 메소드 호출이 정상적으로 종료 된 후
  • @AfterThrowing: 타겟 메소드에서 예외가 발생한 경우

위의 예시로 본다면 타겟 메소드 실행 전과 후에 로그를 남기도록 AOP를 설정해줬다는 걸 알 수 있습니다.

 

이제 조금 더 자세히 Spring에서 AOP의 동작원리에 대해 알아보겠습니다.

 

Spring AOP 동작 원리

Spring AOP에서는 프록시를 사용하게 되는데요, 프록시는 타겟의 역할을 대신해주는 대리자라고 볼 수 있습니다. 

 

예를 들어 위 이미지에서 클라이언트가 타겟을 호출하게 되면,

타겟이 아닌 프록시가 대신 호출되어 부가 기능과 비즈니스 로직을 수행하게 됩니다.

 

정리하자면 다음과 같습니다.

 

  • 스프링은 Aspect의 적용 대상(target)이 되는 객체에 대한 Proxy를 만들어 제공
  • 대상 객체(Target)를 사용하는 코드는 대상객체(Target)를 Proxy를 통해서 간접적으로 접근
  • Proxy는 공통기능(Advice)을 실행한 뒤 대상 객체(Target)의 실제 메서드를 호출하거나 또는 대상객체(Target)의 실제 메소드가 호출된 뒤 공통기능(Advice)을 실행
  • 타겟을 감싸는 프록시는 Runtime에 생성

 

Spring AOP 프록시 종류

Spring에서는 AOP의 프록시를 적용하기 위해 JDK dynamic proxy와 CGLIB을 사용합니다.

 

  • JDK dynamic proxy

JDK dynamic proxy타깃 대상이 Interface를 구현하는 클래스면 인터페이스를 기반으로 프록시 객체를 생성하기 때문에 인터페이스에 정의되지 않는 메서드에 대해서는 AOP가 적용되지 않는 단점이 있습니다. (private 메소드)

 

JDK dynamic proxy는 내부적으로 Reflection을 이용합니다.

 

  • CGLIB

CGLIB타깃 대상이 인터페이스를 구현하고 있지 않고 바로 클래스를 사용한다면, 스프링은 CGLIB를 이용하여 클래스에 대한 프록시 객체를 생성합니다.

 

CBLIB는 대상 클래스를 상속받아 구현합니다. 따라서 클래스가 final인 경우에는 프록시를 생성할 수 없습니다.

 

위에 예시로 봤던 UserService에 AOP를 적용하고 해당 클래스를 출력해보면 아래와 같이 CGLIB이 적용된 걸 알 수 있습니다.

 

System.out.println(userService.getClass().getName());

 

CBLIB이 적용된 UserService

 

Spring에서 제공하는 @Transactional도 Spring AOP 중 하나인데, CGLIB을 활용합니다.

 

실제로 적용되는지 확인해봤는데, 

 

클래스에 어느 하나의 메소드라도 @Transactional이 적용되었다면 해당 클래스는 CGLIB으로 프록시 객체를 사용하는걸 알 수 있었습니다.

 

또한, 클래스에 @Transactional을 적용시켰다면 해당 클래스는 CGLIB으로 프록시 객체를 사용하는걸 알 수 있었습니다.


 

AOP 관련 질문

  • Spring에서 AOP란 무엇인가요?
  • 횡단 관심사(cross-cutting concerns)에 대해 설명해주세요
  • Spring AOP Proxy에 대해 설명해주세요