핵심 용어
타겟 오브젝트(Target Object)
- 실제 비즈니스 로직을 수행하는 객체
ex 스프링에서의 UserService, BoardService와 같은 객체
어드바이스(Advice)
- 타겟 오브젝트의 특정 메서드가 실행될 때 그 앞이나 뒤 혹은 실행 중간에 추가로 수행될 동작을 담은 객체
포인트컷(PointCut)
- 어드바이스가 적용될 지점을 정의하는 표현식으로 메서드 선정 알고리즘을 담은 객체
공통 관심 사항(Cross-cutting-concerns)
- 특정 모듈에 국한되지 않은, 여러 모듈이나 계층에 걸쳐 시스템 전반에 공통적으로 나타나는 기능이나 로직
ex 로깅(Logging), 보안(Security), 트랜잭션 관리(Transaction Management), 예외 처리(Exception Handling), 캐싱(Caching)
에스팩트(Aspect)
- 공통관심사항을 모듈화 한 것으로 포인트컷과 어드바이스로 구성됨
AOP
AOP(Asepect Oriented Programming) 관점 지향 프로그래밍이라 불리며, 공통 관심 사항(Cross-cutting-concerns)을 별도의 모듈로 분리하여 관리하는 개발 방법
➡️ 핵심 기능에 부여되는 부가 기능을 효과적으로 모듈화
이러한 부가 기능들을 분리하여 모듈로 만들고 설계하는 방법이 기존 객체지향 프로그래밍(OOP)의 방식과는 구분되는 특성이 있기에 이를 AOP라는 개념이 생겨나게 되었다.
AOP는 OOP(Object Oriented Programming)를 대체하는 기술이 아닌, OOP를 돕는 보조 기술로서 핵심 기능을 설계하고 구현할 때 객체지향적인 가치를 유지할 수 있도록 도와준다.
AOP를 활용한 코드
import org.springframework.stereotype.Service;
@Service
public class ExampleService {
public void performTask() {
System.out.println("업무 로직 수행");
}
}
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBeforeMethod() {
System.out.println("메서드 실행 전 로그 출력");
}
}
@Aspect를 통해 해당 클래스가 aspect임을 확인하고 @Before를 통해 포인트컷 표현식에 매핑되는 매서드가 실행되기 전에 Advice( logBeforeMethod )를 실행하도록 지정하고 execution을 통해 com.example.service.*.*(..)를 포인트 컷으로 지정함
만약 Service 클래스에서 메서드를 실행하기 전 로그를 출력하는 기능을 넣고 싶다면 해당 패키지를 포인트컷에 추가하면 된다.
Spring AOP
이제 Spring AOP에 동작에 대해 자세히 알아보자. 이를 이해하기 위해서는 프록시 패턴에 대한 이해가 선행되어야 한다.
프록시 패턴(Proxy Pattern)
어떤 객체에 대한 접근을 제어하기 위해 원본 객체를 대신하여 대리인(프록시)을 활용하는 디자인 패턴이다.
동작 과정
Client가 Proxy 객체를 생성하고 Subject Interface를 통해 메서드 호출 ➡️ Proxy가 요청을 가로챈 뒤 추가 작업( ex 공통 관심 사항 )을 수행한 뒤 RealSubject 메서드를 호출하고 이후 Proxy를 통해 Client에 반환한다.
Spring의 AOP 동작
- 다이내믹 프록시 객체의 생성 요청 (@EnableAspectJAutoProxy )
- 포인트컷을 통해 부가 기능 대상 여부 확인
- 어드바이스로 부가 기능 적용
- 실제 기능 처리
Spring AOP 한계
- Spring 컨텍스트와 통합되어 있다➡️ Spring에서는 쉽게 사용가능하나 이는 Spring에 대한 의존성을 갖는 것이므로 다른 프레임워크로의 전환이 어려워질 수 있음.
- 런타임 시 프록시 객체를 생성하여 AOP 적용 ➡️ 바이트 코드 변경 X
- 메서드 수준의 프록시 기반 AOP만 지원 ➡️ 클래스나 필드 수준 조작 X
AspectJ 프레임워크를 활용하면 위와 같은 한계를 모두 극복할 수 있다.
즉 AspectJ는 바이트 코드 조작을 통해 스프링이 없는 환경에서도 AOP를 이용할 수 있으며 이 과정에서 클래스나 필드 수준에서의 조작 또한 가능하다.
AspectJ
AOP프레임워크 중 하나로 프록시를 사용하지 않고 CGlib라는 바이트 조작 라이브러리를 사용하여 타겟 오브젝트의 바이트 코드를 변경하여 부가 기능을 직접 넣어준다. ➡️ Spring 컨테이너의 의존하지 않으며, 프록시 AOP방식보다 유연한 AOP 구현 가능
요약
- Spring AOP는 메서드 수준에서 간단하게 AOP를 적용하려는 경우에 적합하며, Spring 애플리케이션과의 통합에 용이
- AspectJ는 더 강력하고 광범위한 AOP 기능이 필요하거나, 성능이 중요한 경우에 적합
출처