skip to content

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

level: seniorimportance: should knowfreq 30%

answer

  1. bean() = name convention, scattered types
  2. use when classes can't be annotated
  3. same class, two names -> bean() distinguishes
  4. annotations = explicit + refactor-safe
  5. bean() breaks silently on rename; Spring-only

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.

solid answer

~40 s

The choice is about what your target set has in common. within(com.acme.svc..*) selects by package/type location; @within(Service) / @annotation(Audited) select by annotations on the class or method; a custom marker annotation makes intent explicit and refactor-safe. bean(*Service) instead selects by the container bean name. Prefer bean() when: the targets follow a name convention but live in different packages and share no common supertype or annotation; you can't touch third-party classes to annotate them; or you want to distinguish two beans of the same class by name. Prefer annotations when you want intent visible at the target and independence from names; prefer within/execution when a package or type pattern captures the set cleanly. bean() couples advice to names, so renaming a bean silently changes matching — the main trade-off. It's also Spring-AOP-only.

go deeper

for a junior

Know bean() targets by name; annotations/within target by type.

for a middle

Give one scenario where bean() is the natural fit.

for a senior

Weigh name-coupling vs annotation explicitness and the same-class-two-beans case.

for a principal

Set team conventions on when name-based advice is acceptable vs annotation-driven.

## The designator menu | Designator | Selects by | Editable target needed? | Portable to AspectJ | |---|---|---|---| | `execution(...)` | method signature/type pattern | no | yes | | `within(pkg..Type)` | lexical location / type | no | yes | | `@within(Ann)` / `@target(Ann)` | annotation on the class | yes (add annotation) | yes | | `@annotation(Ann)` | annotation on the method | yes | yes | | `bean(namePattern)` | **Spring bean name** | no | **no (Spring-only)** | ## When bean() wins 1. **Name convention, scattered types.** Your services are `com.a.PricingService`, `com.b.orders.OrderService`, `com.c.legacy.BillingService` — no shared package, no shared supertype, no annotation you control. But they're all registered as `*Service`. `bean(*Service)` captures them in one line; `within(...)` would need many package clauses. 2. **Can't modify the targets.** Third-party or generated beans you cannot annotate — annotation-based designators are off the table, but you can still match by the name you register them under. 3. **Same class, different beans.** Two beans of one class registered under different names can be advised differently: `bean(primaryCache)` vs `bean(secondaryCache)` — impossible with type/annotation designators, which can't tell the instances apart. ## When to prefer alternatives - **Explicit intent / refactor safety:** a custom `@Audited` annotation with `@annotation(Audited)` documents the cross-cutting concern at the target and survives renames. bean() is invisible at the target and breaks silently on a rename. - **Type is the real criterion:** if 'everything implementing `Repository`' is the intent, `@within`/type patterns express that precisely; a name convention is a proxy for it and can drift. - **Portability to AspectJ weaving:** bean() is Spring-only; annotation/type designators are not. ## The core trade-off `bean()` trades **decoupling from types** for **coupling to names**. Names are easy to pattern-match and don't require touching classes, but they are also **incidental**: a refactor that renames a bean changes advice application with no compiler warning. For durable, self-documenting cross-cutting concerns, annotations usually age better; for quick, convention-driven or can't-touch-the-class situations, bean() is the pragmatic pick.

  • Two beans are instances of the same class. How do you advise only one of them?
    bean(name) — because it matches by bean name, you can target bean(primaryCache) and leave bean(secondaryCache) unadvised. Type/annotation designators can't distinguish two beans of the same class.
  • What's the durability downside of bean() versus a marker annotation?
    bean() couples advice to incidental bean names; renaming a bean silently changes what's advised with no compiler help. A @Audited annotation makes the concern explicit at the target and survives renames.

saying these in an interview costs you the question

  • Claiming bean() and within() are interchangeable
  • Saying bean() can't distinguish two beans of the same class
  • Recommending bean() when the real criterion is a shared type/annotation

context