What does the args() pointcut designator do in Spring AOP, and how is it different from execution()?
answer
- execution = static signature; args = runtime arg types
- args(name) binds argument by name into advice param
- args is dynamic — runtime type check
- combine with && execution() to narrow
- needs -parameters or argNames for name resolution
basics
~20 sargs() 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.
solid answer
~30 sexecution() matches methods by their declared signature (return type, name, declared parameter types) — it is evaluated statically from the method declaration. args() matches on the runtime types of the actual arguments passed to the call, so it can match subtypes and is inherently dynamic. args() has a second job: naming a parameter, e.g. args(account), binds that runtime argument and passes it into the advice method by name, so you get the value directly instead of digging through JoinPoint.getArgs(). You typically combine them: @Before("execution(* com.app..*(..)) && args(account)") narrows to methods whose first argument is an Account and hands you that Account.
code
java · 18 lines@Aspect
@Component
public class AuditAspect {
// Matches any service method whose first arg is an Account,
// and binds that arg as `account`.
@Before("execution(* com.app.service..*(..)) && args(account)")
public void audit(Account account) {
log.info("Touching account {}", account.getId());
}
// args(String) matches on RUNTIME type — subtypes of String
// (none here) would match; a null argument would NOT match.
@Before("execution(* com.app..*(..)) && args(name)")
public void logName(String name) {
log.debug("first-arg string: {}", name);
}
}go deeper
Know that args() looks at the actual arguments at runtime and can hand a specific argument to your advice by name.
Explain static vs dynamic matching, the binding form args(name), and combining with execution().
Discuss parameter-name resolution, positional semantics with '..', and performance implications of broad dynamic pointcuts.
Reason about when dynamic matching is worth the cost, subtype/null matching edge cases, and designing reusable named pointcuts that bind context safely.
**AOP vocabulary first.** A *join point* is a point during execution — in Spring AOP always a method call on a Spring bean. A *pointcut* is an expression selecting which join points to intercept. *Advice* is the code that runs (e.g. @Before, @AfterReturning). A *pointcut designator* (PCD) is a keyword in the pointcut expression, such as execution(), within(), this(), target(), and args(). **execution()** is the workhorse PCD. It matches on the *static* method signature: `execution(* com.app.Service.save(..))` matches by declared return type, package/class, method name, and declared parameter types. It does not look at the actual runtime values. **args()** matches on the *runtime types of the actual arguments*. `args(java.lang.String)` matches any method invoked with exactly one argument whose runtime type is (or is assignable to) String. Because it inspects runtime types, args() is a *dynamic* pointcut: Spring may need a runtime check on each invocation rather than deciding purely at proxy-creation time. `args(String, ..)` means first arg is a String, followed by zero or more others. **Binding form.** When you write a *name* that is not a known type, e.g. `args(account)`, Spring treats `account` as a binding variable. It must correspond to a parameter of the advice method; the parameter's declared type both constrains the match and receives the value: ```java @Before("execution(* com.app..*(..)) && args(account)") public void audit(Account account) { ... } ``` Here the pointcut matches only methods whose (first) argument is assignable to Account, and Spring passes that argument in as `account`. This is cleaner and type-safe compared to `((Account) joinPoint.getArgs()[0])`. **Parameter-name resolution.** For binding to work, Spring must map the pointcut variable name to the advice parameter name. It does this via (a) the `-parameters` javac flag (or Kotlin, which retains names), (b) debug symbols, or (c) the explicit `argNames` attribute on the annotation. If names can't be resolved you get IllegalArgumentException about parameter name discovery. **Positional meaning.** In `args(a, b)` the order corresponds to the argument order of the intercepted method. To bind an argument that isn't first, use `..`: `args(.., token)` binds the last argument. **When to use.** Use args() binding whenever the advice needs a specific argument's value (auditing, validation, security checks on a domain object). Use execution() to scope by signature. They compose with `&&`, `||`, `!`. **Gotchas.** args() alone (e.g. `@Before("args(String)")`) is legal but very broad and forces runtime checks on many join points — always narrow with execution()/within(). Overloaded methods and null arguments can surprise you: a null argument does not match a type in args().
- Why is args() considered a dynamic pointcut while execution() is static?args() depends on the runtime types/values of the actual arguments, so matching may require a per-invocation check. execution() is decided from the declared method signature, which is known at proxy-creation time.
- How does Spring know which advice parameter to bind args(account) to?By matching the pointcut variable name to an advice parameter name. Parameter names come from the -parameters compiler flag, debug info, or the explicit argNames attribute; otherwise binding fails with a parameter-name-discovery error.
saying these in an interview costs you the question
- Claiming args() matches on the declared parameter types (that's execution()).
- Saying args() binds by position of the advice parameter rather than by name.
- Thinking a null argument still matches args(SomeType).