skip to content

Pointcut Designators

The designators that decide which join points an advice matches — execution, within, this, target, the annotation family, args, and Spring's own bean(). Interviewers ask you to write a pointcut on the spot more often than you would guess.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

29

What does the @annotation pointcut designator match in Spring AOP, and how is it different from designators like execution() or within()?

level: juniorimportance: must knowfreq 55%

answer

  1. method carries the annotation
  2. opt-in by annotation, not by name
  3. RUNTIME retention mandatory
  4. static match, no runtime residue
  5. method annotations not inherited

basics

~10 s

@annotation(SomeAnnotation) matches any method-execution join point where the method being called carries that annotation. Unlike execution()/within(), which match by name or package pattern, @annotation matches by the presence of an annotation on the method.

solid answer

~40 s

@annotation is an annotation-presence pointcut designator: @annotation(com.example.Audited) matches a method-execution join point when the executing method is annotated with @Audited. execution() and within() select join points by signature/type-name patterns; @annotation selects them by the metadata (annotation) present on the method itself, so advice applies wherever developers opt in by adding the annotation, regardless of package or name. The annotation's @Retention must be RUNTIME, or Spring cannot see it. Because it targets the method, it is resolved statically (the method is known at proxy-creation time). It is the conceptual basis for how declarative features like @Transactional and @Cacheable match method-level annotations. You can also bind the annotation instance as an advice parameter to read its attributes.

code

java · 15 lines
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audited { String level() default "INFO"; }

@Aspect
@Component
public class AuditAspect {

    // Matches ANY method annotated with @Audited, regardless of class/package.
    @Around("@annotation(audited)")
    public Object audit(ProceedingJoinPoint pjp, Audited audited) throws Throwable {
        log.info("[{}] {}", audited.level(), pjp.getSignature().toShortString());
        return pjp.proceed();
    }
}

go deeper

for a junior

Know that @annotation matches methods that carry a given annotation, and that retention must be RUNTIME.

for a middle

Contrast with execution()/within(); know it is a static matcher and that you can bind the annotation to read attributes.

for a senior

Articulate the opt-in design, the non-inheritance of method annotations, and how this underpins @Transactional/@Cacheable method-level matching.

for a principal

Discuss trade-offs vs @within/@target for API design, retention/meta-annotation strategy, and why annotation-based designators decouple aspects from package structure.

## What it is Spring AOP pointcut expressions use AspectJ's pointcut language. Besides the common `execution(...)`, `within(...)`, `args(...)` designators, AspectJ provides four **annotation-presence** designators: `@annotation`, `@within`, `@target`, and `@args`. They select join points based on where an annotation is present rather than on class/method names. `@annotation(SomeAnnotation)` matches a **method-execution join point when the method being executed is directly annotated** with `SomeAnnotation`. (In Spring AOP the only join point kind is method execution — there is no field or constructor weaving.) ```java @Retention(RetentionPolicy.RUNTIME) // MANDATORY — Spring reads annotations reflectively at runtime @Target(ElementType.METHOD) public @interface Audited {} @Aspect @Component public class AuditAspect { @Before("@annotation(com.example.Audited)") public void audit(JoinPoint jp) { /* runs before any @Audited method */ } } ``` ## How it differs from execution()/within() - `execution(* com.example.service.*.*(..))` selects by **method signature pattern** (return type, package, class, name, args). - `within(com.example.service..*)` selects by the **type** in which the join point occurs (name pattern). - `@annotation(X)` selects by the **annotation present on the method** — no name or package coupling. Developers opt in per method by adding `@X`. This inversion of control is why annotation designators scale so well: the aspect declares *what capability* to apply, and any method across the codebase can request it by adding the annotation. ## Key requirements and mechanics - **Retention must be `RUNTIME`.** With `SOURCE` or `CLASS` retention the annotation is invisible at runtime and never matches. - `@annotation` is a **static** matcher: whether a method carries the annotation is known when Spring builds the proxy, so there is no per-invocation runtime residue check (unlike `@target`/`@args`). - **Java method annotations are NOT inherited.** If a subclass overrides an annotated method without re-declaring the annotation, `@annotation` no longer matches that overriding method. (Spring's own `@Transactional`/`@Cacheable` support works around this with `AnnotatedElementUtils`/merged-annotation lookup, but a raw `@annotation` pointcut does not.) ## Reading annotation attributes You can **bind** the annotation instance to an advice parameter whose name matches the designator reference, then read its attributes: ```java @Around("@annotation(audited)") public Object around(ProceedingJoinPoint pjp, Audited audited) throws Throwable { String level = audited.level(); // read attribute return pjp.proceed(); } ``` ## When to use Use `@annotation` for **cross-cutting behavior that individual methods opt into**: auditing, custom caching, retry, rate-limiting, metrics timing. It is the cleanest, most explicit of the annotation designators and the safest performance-wise.

  • Why must the annotation have RUNTIME retention?
    Spring AOP inspects annotations reflectively at runtime when matching pointcuts and creating proxies. With SOURCE or CLASS retention the annotation is discarded before runtime, so it is never visible and the pointcut can never match.
  • If a subclass overrides a method annotated with @Audited but doesn't repeat the annotation, does @annotation still match?
    No. Java method-level annotations are not inherited, so the overriding method has no @Audited and the pointcut skips it. You'd have to re-declare the annotation on the override.

saying these in an interview costs you the question

  • Claiming @annotation matches when the annotation is on the class (that's @within/@target)
  • Saying SOURCE/CLASS retention works for AOP matching
  • Believing method annotations are inherited by overrides
  • Confusing @annotation with the @Annotation-on-parameter idea (that's @args)

context

open as a page

What does the args() pointcut designator do in Spring AOP, and how is it different from execution()?

level: juniorimportance: must knowfreq 55%

basics

~20 s

args() matches join points where the method's arguments are of the given types at runtime. execution() matches on the static method signature. args() checks the actual runtime argument types and can also bind an argument into an advice parameter.

open as a page

What does the bean() pointcut designator do in Spring AOP, and how do you use it?

level: juniorimportance: must knowfreq 55%

basics

~10 s

bean(name) limits advice to join points inside Spring beans whose bean name matches the given pattern. For example, bean(tradeService) advises only the bean named tradeService, no matter its type.

open as a page

What does the execution() pointcut designator match, and how would you read execution(public * com.app.service..*.*(..))?

level: juniorimportance: must knowfreq 62%

basics

~10 s

execution() matches method executions. That expression means: any public method, returning any type, in any class inside com.app.service or its sub-packages, with any name and any number of arguments.

open as a page

In Spring AOP, what kind of join points can your aspects actually advise?

level: juniorimportance: must knowfreq 68%

basics

~10 s

Only method executions. Spring AOP wraps beans in proxies, so an aspect can run before/after/around a public method call on a Spring bean — but not field reads/writes, constructors, or static blocks.

open as a page

What is the difference between the @within and @target pointcut designators?

level: middleimportance: must knowfreq 50%

basics

~20 s

Both match when a type carries the annotation, but @within uses the type that declares the executed method (resolved statically), while @target uses the runtime class of the target object (resolved at runtime). They differ when inheritance is involved.

open as a page

How do the returning and throwing attributes combine with args() binding to expose full context to advice?

level: middleimportance: must knowfreq 45%

basics

~20 s

@AfterReturning has a returning attribute that binds the method's return value to a named advice parameter; @AfterThrowing has a throwing attribute that binds the thrown exception. Combined with args() you can access the input argument, the result, or the exception together in one advice.

open as a page

Break down the full grammar of an execution() pointcut. Which parts are optional, and which are required?

level: middleimportance: must knowfreq 48%

basics

~10 s

Grammar: execution(modifiers? ret-type decl-type? name(params) throws?). Required are the return-type pattern, the method-name pattern, and the parameter pattern. Optional are modifiers, the declaring-type prefix, and the throws clause.

open as a page

What happens if you write a Spring AOP pointcut using an AspectJ designator like call(), get(), or set()?

level: middleimportance: must knowfreq 55%

basics

~20 s

Spring rejects it at startup. Using an unsupported designator (call, get, set, initialization, etc.) throws IllegalArgumentException — it is NOT silently ignored. Only Spring's supported subset (execution, within, this, target, args, @annotation, bean, ...) is allowed.

open as a page

What is the difference between the this() and target() pointcut designators?

level: middleimportance: must knowfreq 60%

basics

~20 s

this() tests the AOP proxy object's type; target() tests the underlying real object's type. Both can also bind that object into the advice. They differ when the proxy's type is not the same as the target's type.

open as a page

Explain why this(ConcreteClass) can silently fail to match while target(ConcreteClass) works, and how proxy type selection (JDK vs CGLIB) drives it.

level: seniorimportance: must knowfreq 40%

basics

~20 s

With a JDK dynamic proxy the proxy implements only the target's interfaces, so it is not an instance of the concrete class — this(ConcreteClass) fails. target(ConcreteClass) checks the real object, which is the concrete class, so it matches. CGLIB proxies subclass the concrete class, so both match.

open as a page

What does the within() pointcut designator match in Spring AOP, and how is it different from execution()?

level: juniorimportance: should knowfreq 45%

basics

~10 s

within() matches all join points where the executing method is declared inside a given type or package — for example within(com.example.service..*). It filters by location, not by method signature.

open as a page

How do you bind an annotation instance to advice so you can read its attributes, and what are the parameter-name rules?

level: middleimportance: should knowfreq 40%

basics

~20 s

Reference the annotation by a lowercase name in the designator, e.g. @annotation(retry), and declare an advice parameter of that annotation type with the same name (Retry retry). Spring injects the actual annotation instance so you can call its attribute methods.

open as a page

How does Spring resolve the parameter names used in args() bindings, and what breaks binding?

level: middleimportance: should knowfreq 40%

basics

~20 s

Spring matches the name inside args(name) to an advice method parameter with the same name. It gets those names from the -parameters compiler flag, debug info, or the annotation's argNames attribute. If names aren't available, binding fails with an error.

open as a page

How do wildcards and boolean operators work with bean(), and how would you scope advice to services but exclude a few beans?

level: middleimportance: should knowfreq 38%

basics

~10 s

bean() supports a * wildcard in the name, e.g. bean(*Service), and combines with &&, ||, ! like other pointcuts. To advise services except some beans: bean(*Service) && !bean(legacyService).

open as a page

Explain the difference between the * and .. wildcards in an execution() pointcut, giving package, type, method-name, and parameter examples.

level: middleimportance: should knowfreq 44%

basics

~10 s
  • matches exactly one item (one name segment, one type, one parameter). .. matches zero or more — in package position it spans sub-packages, in the parameter position it spans any number of arguments.
open as a page

What does the @args designator match, and how does it differ from args()? What are its runtime and performance implications?

level: seniorimportance: should knowfreq 30%

basics

~20 s

@args matches when the runtime types of the passed arguments are themselves annotated. @args(Validated) matches a call whose single argument's actual class carries @Validated. args() matches by argument type, not by annotation. @args is a runtime check.

open as a page

How do this() and target() bindings relate to args(), and why can they behave differently under CGLIB vs JDK proxies?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Like args(), the this() and target() designators can bind objects into advice parameters by name. this() binds the proxy (the AOP object), target() binds the underlying target bean. They match on runtime type, and which types match can differ between JDK interface proxies and CGLIB class proxies.

open as a page

Why is bean() described as a Spring-AOP-only designator with no AspectJ equivalent, and what are the consequences?

level: seniorimportance: should knowfreq 40%

basics

~20 s

AspectJ weaves at the class/bytecode level and knows nothing about Spring bean names, so it has no bean() designator. bean() only works inside Spring's proxy-based AOP, where the container maps join points to named beans.

open as a page

When would you choose bean() over within(), @within, or a custom annotation for scoping advice?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Use bean() when the beans you want to advise share a naming convention but not a package, type, or annotation — and you can't or don't want to modify their classes. Use within/@within/@annotation when selection should follow type or annotation instead.

open as a page

A colleague writes execution(* com.app..*.*(..)) but their advice never fires on some methods. What proxy-related reasons could explain this, given how Spring AOP evaluates execution() pointcuts?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Spring AOP is proxy-based, so execution() only advises calls that go through the proxy: external calls to Spring-managed beans. Self-invocation (this.method()), private/final methods, and non-bean objects won't be intercepted even if the pointcut technically matches.

open as a page

Explain why Spring AOP supports execution() but not call(), and what that means for intercepting a method invocation.

level: seniorimportance: should knowfreq 40%

basics

~20 s

call() matches at the caller's side; execution() matches where the method actually runs (callee side). Spring's proxy sits in front of the target, so it can only observe the execution. There's no caller-side hook, hence no call().

open as a page

How do you bind the target object (and arguments) into advice using target()/this()/args(), and what are the semantics of the bound reference?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Instead of a type, name a variable in the PCD (e.g. target(svc)) and declare a matching parameter in the advice method; Spring passes the object in. this() binds the proxy, target() binds the real object, args() binds arguments. The parameter's declared type supplies the instanceof check.

open as a page

How do the annotation-presence designators relate to how Spring matches @Transactional and @Cacheable, and what subtleties (inheritance, interfaces, runtime designators) should you be aware of at scale?

level: principalimportance: should knowfreq 28%

basics

~20 s

@Transactional/@Cacheable are matched by dedicated Spring pointcuts that, like @annotation plus @within, look for the annotation on the method and fall back to the class. They add merged-annotation and meta-annotation support that a raw @annotation pointcut lacks.

open as a page

What are the correctness and performance implications of relying on dynamic args() matching, and how would you design pointcuts to avoid its pitfalls?

level: principalimportance: should knowfreq 18%

basics

~20 s

args() is dynamic, so Spring may check argument types at every invocation, which is slower and harder to reason about than static matching. Narrow with execution()/within() first, keep bound pointcuts small and reusable, and remember null and autoboxing edge cases can silently skip matches.

open as a page

A requirement needs you to intercept field writes and constructor calls across your codebase. How does Spring AOP's supported-designator subset constrain you, and what's the correct architectural move?

level: principalimportance: should knowfreq 22%

basics

~20 s

Spring AOP can't do it — it only advises method executions, so get/set (fields) and constructor join points aren't available. The move is to adopt full AspectJ via load-time or compile-time weaving, which supports the entire join-point model.

open as a page

When architecting pointcuts across a large codebase, how do within(), this() and target() differ in matching cost and expressiveness, and how would you combine them?

level: principalimportance: should knowfreq 20%

basics

~20 s

within() is a static, type/package match resolved at proxy creation — cheap, coarse, no binding. this()/target() are dynamic type tests on the proxy/target, can bind objects, but are per-call in the general case. Scope broadly and cheaply with within()/execution(), then AND a dynamic this()/target() only where you need object identity or binding.

open as a page

What subtle behaviors of bean() around bean naming, aliases, FactoryBeans, and infrastructure beans should you know?

level: principalimportance: nice to knowfreq 16%

basics

~20 s

bean() matches the container's registered bean name. For a FactoryBean it matches the produced object's name (not the &name factory), it can't advise infrastructure/non-proxied beans, and it matches names not aliases in a predictable way — so know exactly what name a bean carries.

open as a page

As a lead, when would you choose execution() over within(), this(), target(), or @annotation for a pointcut — and how do you keep execution() expressions maintainable across a large codebase?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Use execution() when you need signature-level precision (return type, name, args). Use within() for coarse type/package scope, @annotation for marker-driven cross-cutting, and this()/target() for proxy/target type checks. Keep it maintainable by centralizing named @Pointcut methods and composing them.

open as a page