AOP (Aspect Oriented Programming)
- 횡단 관심사 (Cross-Cutting Concern)의 분리를 허용함으로써 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임
- 여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 개발자는 반복 작업을 줄이고 핵심 기능 개발에만 집중할 수 있다.
Example
- 팩토리얼 연산을 재귀로 구현한 함수의 실행시간을 측정.
- AOP를 이용하지 않으면 해당 함수에 실행시간을 측정하는 로직을 추가해야 됨
- 위와 같은 상황을 해결하기 위해 프록시를 사용
Proxy

- 자신이 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 것 (대리인, 대리자)
- 사용 목적
- 클라이언트가 타겟에 접근하는 방법을 제어 -> 프록시 패턴
- 타겟에 부가적인 기능을 부여 -> 데코레이터 패턴
Example

- 실행시간을 구현한 ExecutionTimeCalcuator라는 프록시 객체 구현
- 생성자 인자로 실제로 시간 측정 계산을 진행할 delegate 인자를 받는다.

- 이런 식으로 실제로 계산할 Calculator의 의존성을 프록시에 주입해준다.
다시 AOP

- 핵심 기능인 계산하기와 부가 기능인 실행시간 측정, 로깅
- 즉, 부가 기능에서 바라보는 공통된 부분을 추출하는 것이 AOP의 개념. 이 부가 기능을 횡단 관심사 (Cross-Cutting Concern)라고 부른다.
AOP 용어
- Target Object: 부가 기능을 부여할 대상
- Aspect: AOP의 기본 모듈. 부가될 기능을 정의한 Advice와 Advice를 어디에 적용할지 결정하는 Pointcut을 함께 가진다.
- Advice: 타겟에게 제공할 부가 기능을 담은 모듈. 타겟이 필요없는 순수한 부가 기능. Aspect가 무엇을 언제 할지 정의
- Pointcut: Advice에 적용할 JoinPoint를 선별하는 작업 또는 그 기능을 정의한 모듈
- Joinpoint: 프로그램의 실행 내부에서 Advice(부가 기능)가 적용될 수 있는 위치

Spring AOP
용어
- Target Object: Spring AOP는 런타임 프록시로 구현되므로 타겟은 항상 프록시이다.
- Aspect: 트랜잭션 관리가 가장 좋은 예시. @Aspect를 사용하여 구현
- Advice: Around, Before, AfterThrowing 등 다양한 Advice가 존재
- joinPoint: Spring AOP는 프록시 방식을 사용하므로 joinPoint는 항상 메서드 실행 지점이다.
- pointcut: Spring AOP의 joinPoint는 메서드의 실행이므로, 메서드를 선정하는 기능을 한다.
구현
- 런타임 시점에 프록시 객체를 생성하여 공통 기능 삽입
- 컴파일러나 클래스 로더를 설정하지 않아도 된다.
- 프록시는 메서드 오버라이딩 개념으로 동작하기 때문에, 스프링 AOP는 메서드 실행 시점에만 AOP를 적용할 수 있다.
- 스프링 컨테이너가 관리할 수 있는 빈에만 AOP를 적용할 수 있음.
- AspectJ를 직접 사용하는 것이 아닌 AspectJ의 문법을 차용하고 프록시 방식의 AOP 적용
스프링 AOP는 메서드 실행 시점에만 AOP를 적용할 수 있다?
public class A {
public void doSomething() {
System.out.println("메서드 실행 중...");
}
}
- A라는 클래스에는 doSomething()이라는 메서드가 있고, 어떤 작업을 수행하고 결과를 반환한다.
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.A.doSomething(..))")
public void beforeDoSomething(JoinPoint joinPoint) {
System.out.println("메서드 실행 전에 로깅 수행");
}
@After("execution(* com.example.A.doSomething(..))")
public void afterDoSomething(JoinPoint joinPoint) {
System.out.println("메서드 실행 후에 로깅 수행");
}
}
- Spring AOP를 사용하여 doSomething() 메서드 실행 전후에 로깅을 추가
- @Before 어노테이션이 붙은 beforeDoSomething() 메서드는 doSomething() 메서드 실행 전에 로깅을 수행하고, @After 어노테이션이 붙은 afterDoSomething() 메서드는 doSomething() 메서드 실행 후에 로깅을 수행한다.
메서드 실행 전에 로깅 수행
메서드 실행 중...
메서드 실행 후에 로깅 수행
- 이를 통해 Spring AOP에서 joinPoint를 사용하여 메서드 시점 추가 동작을 수행할 수 있다는 것을 알 수 있다.
- execution에서 doSomething을 제외해도 결과는 같다.
Advice
- @Around: 메서드 실행 , 후 또는 익셉션 발생 시점
- @Before: 메서드 호출 전
- @AfterReturning: 메서드가 익셉션 없이 실행된 이후
- @AfteThrowing: 메서드를 실행하는 도중 익셉션이 발생한 경우
- @AfterAdvice: 익셉션 발생 여부 상관없이 메서드 실행 후