Mastering Spring AOP Pointcut Expressions and the @Aspect Annotation

Understanding Spring AOP Proxies

When working with Spring AOP, it's crucial to understand that only method calls through Spring-managed beans will trigger aspect advice. Direct this calls bypass the proxy mechanism entirely, meaning aspects won't intercept them. This happens because service objects are injected as Spring proxies, which are separate from objects created via this.

Pointcut Expressions

Core Expression Types

@Pointcut(value="execution(* com.example.UserService.*(..))")

The @Pointcut annotation defines reusable pointcuts using various expression types:

execution()    - Matches method execution join points
args()         - Matches method executions with specific parameter types
this()         - Matches execution on AOP proxy objects of a given type
target()       - Matches execution on target objects (not including introduced interfaces)
within()       - Matches method executions within specified types
@args()        - Matches executions where method arguments carry specific annotations
@target()      - Matches executions on types marked with specific annotations
@within()      - Matches all method executions within types carrying specific annotations
@annotation()  - Matches methods annotated with a specific annotation

Execution Expression Syntax

execution(
    modifier-pattern?      // public, private, protected (optional)
    ret-type-pattern      // return type
    declaring-type-pattern? // class path (optional)
    name-pattern(param-pattern) // method name and parameters
    throws-pattern?       // exception type (optional)
)

Common Patetrns

execution(public * *(..))                           // Any public method
execution(* set*(..))                                // Methods starting with 'set'
execution(* com.example.service.AccountService.*(..)) // All methods in AccountService
execution(* com.example.service.*.*(..))            // All methods in the service package
execution(* com.example.service..*.*(..))           // All methods in service and subpackages
execution(* com.example.aop..*.*(..))               // All methods in aop package and subpackages

Wildcard Characters

  • * matches any sequence of characters
  • .. in type patterns matches any number of subpackages; in parameter patterns matches any number of parameters
  • + matches subtypes of a given type (only valid as a suffix)

Practical Example: Method Execution Time Tracking

Enabling Annotation

package com.demo.aop;

import org.springframework.context.annotation.Import;
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PerformanceAspect.class)
public @interface EnablePerformanceMonitor {
}

Method Annoattion

package com.demo.aop;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Timed {
}

Aspect Implementation

package com.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class PerformanceAspect {

    /**
     * Pointcut targeting methods annotated with @Timed
     */
    @Pointcut("@annotation(com.demo.aop.Timed)")
    public void timedMethods() {
    }

    @Around(value = "timedMethods()")
    public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        System.out.println("Executing: " + methodName);
        
        long startTime = System.nanoTime();
        Object result = joinPoint.proceed(joinPoint.getArgs());
        long endTime = System.nanoTime();
        
        long durationNanoseconds = endTime - startTime;
        String formattedTime = (durationNanoseconds / 1_000_000) + " ms";
        System.out.println("Duration: " + formattedTime);
        
        return result;
    }
}

Usage

Annotate any Spring bean method with @Timed to enable automatic execution time logging:

@Service
public class UserService {

    @Timed
    public User findById(Long id) {
        // Method execution will be timed automatically
    }
}

Enable the aspect by adding @EnablePerformanceMonitor to your configuration class or main application class.

Tags: java Spring aop aspectj Pointcut

Posted on Fri, 29 May 2026 22:48:47 +0000 by MajusC00L