스프링 AOP에서 포인트컷(Pointcut) 표현식은 특정 조건에 따라 어드바이스(Advice)가 적용될 메서드를 필터링하는 데 사용됩니다. 포인트컷 표현식을 통해 클래스나 메서드 이름, 매개변수, 접근 제어자 등에 따라 어드바이스가 적용될 메서드를 지정할 수 있습니다.
스프링 AOP에서 포인트컷 표현식을 작성하는 기본 문법을 한글로 정리하겠습니다. 포인트컷 표현식은 특정 조건을 설정해 어드바이스가 실행될 메서드를 선택할 수 있게 해주는 문법입니다.
execution - 메서드 실행 시점을 기준으로 필터링메서드의 이름, 접근 제어자, 리턴 타입, 매개변수 타입 등을 기준으로 특정 메서드에 어드바이스를 적용할 때 사용됩니다.
execution(접근제어자 리턴타입 클래스명.메서드명(파라미터타입))
execution(* com.example.service.*.*(..))com.example.service 패키지에 있는 모든 클래스의 모든 메서드에 적용.execution(public * *(..))public인 모든 메서드에 적용.execution(* set*(..))set으로 시작하는 모든 메서드에 적용.within - 특정 클래스나 패키지 내에서 필터링특정 패키지나 클래스에 속한 메서드들에 어드바이스를 적용할 때 사용됩니다.
within(패키지명.클래스명)
within(com.example.service.*)com.example.service 패키지 내의 모든 클래스에 적용.within(com.example.service..*)com.example.service 패키지와 그 하위 패키지에 있는 모든 클래스에 적용.within(com.example.MyClass)com.example.MyClass 클래스 내의 모든 메서드에 적용.args - 메서드의 파라미터 타입을 기준으로 필터링특정 타입의 파라미터를 가지는 메서드에 어드바이스를 적용할 때 사용됩니다.
args(파라미터 타입)
args(String)String 타입인 메서드에 적용.args(String, ..)String 타입이고, 이후 임의의 파라미터를 가지는 메서드에 적용.@annotation - 특정 어노테이션이 적용된 메서드에 필터링특정 어노테이션이 붙은 메서드에 어드바이스를 적용할 때 사용됩니다.
@annotation(어노테이션 타입)
@annotation(org.springframework.transaction.annotation.Transactional)@Transactional 어노테이션이 붙은 메서드에만 적용.@within - 특정 어노테이션이 클래스 레벨에 적용된 경우 필터링특정 어노테이션이 클래스에 적용된 경우, 그 클래스의 모든 메서드에 어드바이스를 적용합니다.
@within(어노테이션 타입)
@within(org.springframework.stereotype.Service)@Service 어노테이션이 붙은 클래스의 모든 메서드에 적용.@target - 특정 어노테이션이 적용된 빈의 메서드에 필터링특정 어노테이션이 붙은 빈의 모든 메서드에 어드바이스를 적용합니다.
@target(어노테이션 타입)
@target(org.springframework.stereotype.Repository)@Repository 어노테이션이 붙은 빈의 모든 메서드에 적용.@args - 특정 어노테이션이 붙은 파라미터를 가지는 메서드에 필터링파라미터 중 특정 어노테이션이 붙은 인자를 가진 메서드에 어드바이스를 적용합니다.
@args(어노테이션 타입)
@args(org.springframework.stereotype.Repository)@Repository 어노테이션이 붙은 인자를 가진 메서드에 적용.포인트컷 표현식은 &&(AND), ||(OR), !(NOT) 연산자를 사용하여 조합할 수 있습니다.
&&): 두 조건을 모두 만족할 때 적용execution(* com.example..*(..)) && @annotation(org.springframework.transaction.annotation.Transactional)||): 두 조건 중 하나라도 만족할 때 적용within(com.example.service.*) || within(com.example.repository.*)!): 특정 조건을 제외할 때 사용execution(* com.example..*(..)) && !within(com.example.excluded.*)execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)execution(* com.example.service.*.*(..)): com.example.service 패키지 내의 모든 클래스에 속한 메서드에 적용.execution(public * *(..)): 접근제어자가 public인 모든 메서드에 적용.execution(* set*(..)): set으로 시작하는 모든 메서드에 적용.within(type-pattern)within(com.example.service.*): com.example.service 패키지 내의 모든 클래스에 적용.within(com.example.service..*): com.example.service 패키지와 하위 패키지의 모든 클래스에 적용.args(argument-pattern)args(String): String 타입의 인자를 받는 메서드에 적용.args(String, ..): 첫 번째 파라미터가 String 타입이고, 이후 임의의 인자가 있는 메서드에 적용.@annotation(annotation-type)@annotation(org.springframework.transaction.annotation.Transactional): @Transactional이 붙은 메서드에만 적용.@within(annotation-type)@within(org.springframework.stereotype.Service): @Service가 적용된 클래스의 모든 메서드에 적용.@target(annotation-type)@target(org.springframework.stereotype.Repository): @Repository가 붙은 모든 빈의 메서드에 적용.@args(annotation-type, ..)@args(org.springframework.stereotype.Repository): 인수로 @Repository 어노테이션이 있는 메서드에 적용.포인트컷 표현식은 && (AND), || (OR), ! (NOT) 논리 연산자를 통해 조합할 수 있습니다.
execution(* com.example.service.*.*(..)) && @annotation(org.springframework.transaction.annotation.Transactional)within(com.example.service.*) || within(com.example.repository.*)execution(* com.example..*(..)) && !within(com.example.excluded.*)@Aspect
@Component
public class LoggingAspect {
// 특정 메서드 이름을 가진 메서드들에 대해 Advice 적용
@Before("execution(* com.example.service.*.find*(..))")
public void logBeforeFindMethods() {
System.out.println("메서드 시작 전 로그...");
}
// 특정 어노테이션이 붙은 메서드에만 적용
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object logTransactionalMethods(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("트랜잭션 메서드 실행 전...");
Object result = joinPoint.proceed();
System.out.println("트랜잭션 메서드 실행 후...");
return result;
}
}