[스프링 핵심 고급편 (7)] : Spring AOP

Loopy·2023년 1월 9일
0

스프링

목록 보기
11/16
post-thumbnail

☁️ 들어가기 : 핵심 기능과 부가 기능

핵심 기능이란, 해당 객체가 제공하는 주요 기능이다. 반면 부가 기능은 로그 추적기와 같이 핵심 기능을 보조하기 위해 사용되는 기능을 의미한다.

하지만 주로 하나의 부가 기능이 여러 곳에서 동일하게 사용이 되고는 하는데, 이를 횡단 관심사(cross-cutting concerns)라고 한다. 여러 기능들 사이에 걸쳐서 들어가는 관심사라는 뜻이다.

부가 기능 적용의 문제점

  1. 부가 기능을 적용할 때 아주 많은 반복이 필요하다.
  2. 부가 기능이 여러 곳에 퍼져서 중복 코드를 만들어낸다.
  3. 부가 기능을 변경할 때 중복 때문에 많은 수정이 필요하게 된다.
  4. 부가 기능의 적용 대상을 변경할 때 많은 수정이 필요하다.

소프트웨어에서 변경 지점은 하나가 될 수 있도록 모듈화하는 것이 필요한데, 부가 기능과 같은 특정 로직을 애플리케이션 전반에 적용하는 것은 일반적인 OOP 방식으로는 위의 문제점을 해결하기 힘들다.

☁️ AOP와 Aspect

위에서 언급한 횡단 관심사 문제를 해결하기 위해, 부가 기능을 핵심 기능에서 완전히 분리하고 한곳에서 관리할 수 있는 방법을 만들었다. 이렇듯 부가 기능과, 부가 기능을 어디에 적용할지 합해서 하나의 모듈로 만든 것을 Aspect 라고 한다.(이전에 배웠던 Advisor 와 유사)

그리고 AOP(Aspect-Oriented Programming) 이란, 관점 지향 프로그래밍으로 Aspect 를 사용한 프로그래밍 방식을 의미한다. 스프링 AOPAOP 구현의 대표적인 프레임워크인 AspectJ의 일부 기능만 차용해서 제공해준다.

🔖 참고 사항
OOP 를 대체하기 위한 것이 아니라 횡단 관심사를 깔끔하게 처리하기 어려운 OOP 의 부족한 부분을 보조하는 목적으로 개발

☁️ AOP 적용 방식

그렇다면 AOP를 사용할 때 부가 기능 로직은 어떤 방식으로 실제 로직에 추가될 수 있을까?

1. 컴파일 시점

.java 소스코드를 컴파일러를 통해 .class 로 변환하는 시점에 바이트 코드를 조작하여 부가 기능 로직을 추가하는 방식이다. 단, AspectJ 컴파일러만이 부가 기능 로직 대상 클래스가 맞는지 확인하고 적용해줄 수 있다는 단점이 존재한다.

📚 위빙(Weaving)
원본 로직에 부가 기능 로직이 추가되는 작업

2. 클래스 로딩 시점

클래스 로더를 통해 .class 파일을 JVM 메모리에 로딩하는 시점에 바이트 코드를 조작해 부가 기능 로직을 추가하는 방식이다. 단, 로드 타임 위빙은 자바를 실행할 때 특별한 옵션(java -javaagent)을 통해 클래스 로더 조작기를 지정해야 하는데, 이 부분이 번거롭고 운영하기 어렵다.

3. 런타임 시점(프록시)

컴파일 및 클래스까지 로딩이 마친 이후이기 때문에 자바가 아닌 스프링 컨테이너의 도움을 받아서 부가 기능 로직을 추가하는 방식이다. 자바의 main 메서드 실행 이후이기 때문에, 자바가 제공하는 범위 내에서 부가 기능을 적용해야 한다. (스프링 컨테이너, 프록시, DI, 빈 포스트 프로세서와 같은 개념 etc)

실제 대상 코드에 부가 기능 로직이 추가되는 컴파일과 로드 타임 위빙과 다르게 실제 대상 코드는 유지되며, AspectJ 없이 프록시로만 부가 기능을 적용할 수 있다는 장점이 있다. 하지만 프록시이기 때문에 메서드에만 적용 가능하다는 제한이 존재한다.

🔗 AspectJ가 아닌 Spring AOP를 사용하는 이유

사실, AOP는 메서드 호출 지점뿐만 아니라 다른 조인 포인트에서도 적용 가능하다.

📚 조인 포인트
부가 기능 로직이 적용되는 대상을 의미한다. 일반 메서드, 생성자, static 메서드, 필드 값 등을 모두 조인 포인트라 한다.

AspectJ를 사용한다면 컴파일과 로딩 타임에 바이트 코드를 조작할 수 있기 때문에 모든 지점에 적용 가능하지만, 스프링 AOP는 런타임(프록시) 방식을 사용하기 때문에 메서드 실행 시점에만 적용 가능하다.

프록시는 기본적으로 오버라이딩 개념으로 동작하는데, 일반 메서드를 제외한 static 메서드, 필드, 생성자에는 오버라이딩이 불가능하기 때문이다. 따라서 스프링 AOP의 조인 포인트는 메서드 실행으로 제한된다. 또한, 스프링 빈에만 AOP를 적용할 수 있다.

하지만 그럼에도 프록시 방식을 사용하는 스프링 AOP 만의 거대한 장점은, 바로 특별한 자바 설정(컴파일러, 실행 옵션 등)없이 스프링만 있다면 실행이 가능하다는 것이다. 따라서 실무에서는 Spring AOP 를 사용한다.

☁️ AOP 용어 정리

1. 조인 포인트(Join Point)

어드바이스가 적용될 수 있는 위치이다. 즉, 어플리케이션 실행의 모든 지점이 가능하기 때문에 추상적인 개념이다. 스프링 AOP에서의 조인 포인트는 프록시 사용으로 인해 메서드 실행 시점으로 제한된다.

2. 포인트컷(PointCut)

조인 포인트 중에서 어드바이스를 적용할 위치를 선별하는 기능이다. 주로 AspectJ 표현식을 사용해 지정한다.

3. 타켓(Target)

어드바이스를 받는 실제 객체이며, 포인트컷으로 결정된다.

4. 어드바이스(Advice)

부가 기능 로직이다. Around (주변), Before(전), After(후)와 같은 다양한 종류의 어드바이스가 존재한다.

5. 어스펙트(Aspect)

어드바이스와 포인트컷을 하나로 모듈화 한것이다. 여러 어드바이스(N)과 하나의 포인트컷이 존재할 수 있다.

6. 어드바이저(Advisor)

스프링 AOP에서만 사용되는 개념으로 하나의 어드바이스와 하나의 포인트컷으로 구성된다.

7. AOP 프록시

AOP 기능을 구현하기 위해 만든 프록시 객체이다. 스프링에서 AOP 프록시는 JDK 동적 프록시 또는 CGLIB 프록시이다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!

0개의 댓글