Can a named @Pointcut declare parameters, and how are they used to bind values into advice?
answer
- params on @Pointcut = pointcut params
- args()/this()/target()/@annotation() bind by name
- advice repeats the param name
- needs -parameters for name matching
- forward params through composition
basics
~20 sYes. The @Pointcut method's parameters become the pointcut's parameters. Binding designators like args(), this(), target() and @annotation() tie a matched value to a named parameter, and advice with the same parameter names receives that value.
solid answer
~30 sA named pointcut isn't limited to pure matching — it can also *bind* context. You give the @Pointcut method parameters, then use binding forms of designators (args(name), this(name), target(name), @annotation(name), @args(name)) that reference those parameter names. When advice references the pointcut and declares matching parameter names, Spring passes the bound values in. Example: @Pointcut("execution(* *..*Service.*(..)) && args(id,..)") void serviceCallWithId(Long id) {}, then @Before("serviceCallWithId(id)") public void log(Long id). Parameter binding by name is why the pointcut method's parameter list matters. When the composite only needs to test membership (not extract a value), no parameters are needed.
code
java · 20 lines@Aspect
@Component
public class RetryAspect {
// Bind the @Retry annotation instance to a pointcut parameter
@Pointcut("@annotation(retry)")
void retryable(Retry retry) {}
@Around("retryable(retry)") // pass the bound name
public Object around(ProceedingJoinPoint pjp, Retry retry) throws Throwable {
int attempts = 0;
while (true) {
try {
return pjp.proceed();
} catch (Exception e) {
if (++attempts >= retry.maxAttempts()) throw e;
}
}
}
}go deeper
Usually just knows no-parameter named pointcuts.
Aware args()/@annotation() can bind, can copy a working example.
Explains name-based binding, -parameters requirement, and threading params through composites.
Weighs binding vs plain selection, and the operational cost of relying on parameter-name retention across the build.
**Two jobs of a pointcut.** Matching (does this join point qualify?) and, optionally, *binding* — extracting values (arguments, the target object, an annotation instance) and handing them to advice as typed parameters. Named pointcuts support both. **Declaring parameters.** Add parameters to the `@Pointcut` method signature; these become the pointcut's formal parameters. Inside the expression, *binding designators* reference them by name: - `args(name, ..)` — binds a method argument to `name` (`..` allows other args). - `this(name)` — binds the proxy/this object. - `target(name)` — binds the target object being advised. - `@annotation(name)` — binds the annotation instance present on the method. - `@args(name)`, `@within`, `@target` — annotation-on-argument/type variants. ```java @Pointcut("execution(* com.app..*Service.*(..)) && args(orderId,..)") void serviceCallWithOrderId(Long orderId) {} ``` **Consuming the binding in advice.** The advice references the pointcut *passing the parameter names*, and declares matching-named, matching-typed parameters: ```java @Before("serviceCallWithOrderId(orderId)") public void audit(Long orderId) { log.info("service call for order {}", orderId); } ``` Spring matches by **name**, not position, so the pointcut parameter name and the advice parameter name must agree. (This name-matching relies on parameter-name info; modern Spring reads it via the `-parameters` compiler flag or debug info.) **@annotation binding — a very common use.** Bind the annotation instance to read its attributes: ```java @Pointcut("@annotation(retry)") void retryable(Retry retry) {} @Around("retryable(retry)") public Object aroundRetry(ProceedingJoinPoint pjp, Retry retry) throws Throwable { int max = retry.maxAttempts(); // ... } ``` **Threading parameters through composition.** If you compose a binding pointcut into another, the outer pointcut must also declare and forward the parameter: ```java @Pointcut("serviceCallWithOrderId(orderId) && inTxLayer()") void txServiceCallWithOrderId(Long orderId) {} ``` **Gotchas.** - Name mismatch between pointcut param and advice param → binding fails / IllegalArgumentException at startup. - Missing parameter names at runtime (no `-parameters`, no debug symbols) can break name-based binding; enable `-parameters`. - `args(id,..)` matches by runtime argument *type* to the declared parameter type; a wrong type won't match. - A `ProceedingJoinPoint`/`JoinPoint` parameter in advice is separate from bound parameters and doesn't need to appear in the pointcut. - Pure membership pointcuts should have **no** parameters — adding unused ones just invites confusion. **When to use.** Use binding when advice needs the actual value — an id, the target bean, or an annotation's attributes (retry counts, cache keys, permission names). Use plain no-parameter named pointcuts when you only need to select where advice runs.
- How does Spring match a bound pointcut parameter to the advice parameter — by position or by name?By name. The name used in the pointcut binding (e.g. args(orderId)) must match the advice method's parameter name (Long orderId). This requires parameter-name info at runtime — compile with -parameters (or debug symbols) so names are retained.
- You want to read a custom annotation's attributes inside @Around advice — which designator and shape do you use?Bind with @annotation(x) in a @Pointcut declaring that annotation type as a parameter — @Pointcut("@annotation(retry)") void retryable(Retry retry){} — then reference retryable(retry) from the advice and declare Retry retry, reading retry.maxAttempts() etc.
saying these in an interview costs you the question
- Thinking named pointcuts can only match, never bind values
- Assuming binding is positional rather than by parameter name
- Forgetting that composition must forward the bound parameter