AOP(Aspect-Oriented Programming)는 기존과 다른 프로그램 구조 사고 방식을 제공함으로써 객체 지향 프로그래밍(OOP)의 부족한 부분을 보완한다.
객체를 잘 활용하기 위해선 관심사 분리 (Separation of Concerns, SoC)의 디자인 원칙을 준수해야 한다.
관심사의 분리는 모듈화의 핵심이다.
AOP의 핵심 기능과 부가 기능
애플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있다.
핵심 기능(Core Concerns)
부가 기능(CROSS-CUTTING CONCERNS)
핵심 기능을 보조하기 위해 제공되는 기능.
로그 추적 로직, 보안, 트랜잭션 기능 등이 있다.
단독으로 사용되지 않고 핵심 기능과 함께 사용된다.
AOP의 용어 및 개념들
포인트컷 지시자 종류
1. execution : 메서드 실행 조인트 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하며, 기능도 복잡하다.
2. within : 특정 타입 내의 조인 포인트를 매칭한다.
3. args : 인자가 주어진 타입의 인스턴스인 조인 포인트
4. this : 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트
5. target : Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트
execution을 가장 많이 사용하고 나머지는 자주 사용하지 않는다.
모든 공개 메서드 실행
execution(public * *(..))
set 다음 이름으로 시작하는 모든 메서드 실행
execution( set(..))
AccountService 인터페이스에 의해 정의된 모든 메소드의 실행
execution( com.xyz.service.AccountService.(..))
service 패키지에 정의된 메서드 실행
execution( com.xyz.service..*(..))
서비스 패키지 또는 해당 하위 패키지 중 하나에 정의된 메서드 실행
execution( com.xyz.service...*(..))
서비스 패키지 내의 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
within(com.xyz.service.*)
서비스 패키지 또는 하위 패키지 중 하나 내의 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
within(com.xyz.service..*)
AccountService 프록시가 인터페이스를 구현하는 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
this(com.xyz.service.AccountService)
AccountService 대상 객체가 인터페이스를 구현하는 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
target(com.xyz.service.AccountService)
단일 매개변수를 사용하고 런타임에 전달된 인수가 Serializable과 같은 모든 조인 포인트 (Spring AOP에서만 메소드 실행)
args(java.io.Serializable)
대상 객체에 @Transactional 애너테이션이 있는 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
@target(org.springframework.transaction.annotation.Transactional)
실행 메서드에 @Transactional 애너테이션이 있는 조인 포인트 (Spring AOP에서만 메서드 실행)
@annotation(org.springframework.transaction.annotation.Transactional)
단일 매개 변수를 사용하고 전달된 인수의 런타임 유형이 @Classified 애너테이션을 갖는 조인 포인트(Spring AOP에서만 메서드 실행)
@args(com.xyz.security.Classified)
tradeService 라는 이름을 가진 스프링 빈의 모든 조인 포인트 (Spring AOP에서만 메서드 실행)
bean(tradeService)
와일드 표현식 Service 라는 이름을 가진 스프링 빈의 모든 조인 포인트
bean(Service)
AOP 사용예제
@Aspect
public class TimeTraceAop {
@Around("execution(* jpabook.jpashop..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START: " + joinPoint.toString());
try {
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
}
}
}