skip to content

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%

answer

  1. is the only wildcard, no regex
  2. exact / prefix* / *suffix / *infix*
  3. &&, ||, ! full boolean algebra
  4. exclude: bean(*Service) && !bean(legacy*)
  5. name-based, ignores type

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).

solid answer

~40 s

Inside bean(...) you can use the * wildcard to match name fragments: bean(*Service) matches any bean whose name ends in Service, bean(user*) matches any starting with user, bean(tradeService) is an exact match. bean() participates in the full pointcut boolean algebra: && (both), || (either), ! (negate). So you compose expressions like bean(*Service) || bean(*Facade) to cover two conventions, or bean(*Service) && !bean(internalService) to advise all services except one. You typically AND it with a signature designator to also constrain the method, e.g. execution(public * *(..)) && bean(*Service). Naming your @Pointcut methods and reusing them keeps complex expressions readable. Note the wildcard only spans a name segment; there's no regex — just *.

code

java · 16 lines
java
@Aspect
@Component
public class TxLoggingAspect {

    // All services and repositories, but never the sandbox/legacy ones
    @Around("(bean(*Service) || bean(*Repository)) && !bean(sandbox*)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long t = System.nanoTime();
        try {
            return pjp.proceed();
        } finally {
            System.out.printf("%s took %d us%n",
                pjp.getSignature().toShortString(), (System.nanoTime() - t) / 1000);
        }
    }
}

go deeper

for a junior

Know * works and && / || / ! combine terms.

for a middle

Write an exclusion expression and pair negation with a positive term.

for a senior

Explain precedence, named @Pointcut reuse, and name-vs-type mismatch.

for a principal

Design maintainable convention-based advice and reason about match-surface risk.

## Wildcards inside bean() `bean(...)` accepts a bean-name pattern where `*` is a wildcard matching any run of characters within the name: - `bean(tradeService)` — **exact** bean name. - `bean(*Service)` — any name **ending** in `Service`. - `bean(user*)` — any name **starting** with `user`. - `bean(*order*)` — any name **containing** `order`. There is no full regex — only the `*` glob. Matching is against the bean **id/name** the container assigned. ## Boolean composition `bean()` is a normal pointcut term, so it composes with the standard operators, in precedence `!` > `&&` > `||` (parenthesize to be explicit): - **AND** `&&` — intersect: `execution(* *(..)) && bean(*Service)` = advised methods **in** `*Service` beans. - **OR** `||` — union: `bean(*Service) || bean(*Repository)` = beans matching either convention. - **NOT** `!` — exclude: `bean(*Service) && !bean(legacy*)` = every service **except** those named `legacy*`. ## Idiomatic exclusion pattern ```java @Aspect @Component class MetricsAspect { @Pointcut("bean(*Service)") void anyService() {} @Pointcut("bean(legacyPricingService) || bean(sandbox*)") void excluded() {} @Around("anyService() && !excluded()") Object meter(ProceedingJoinPoint pjp) throws Throwable { return pjp.proceed(); } } ``` Named `@Pointcut` methods make the intent readable and reusable, which matters as the expression grows. ## Gotchas - The wildcard matches the **name**, so a class `TradeService` registered under an explicit `@Bean("pricing")` name is **not** matched by `bean(*Service)` — only `bean(pricing)` would. - `!bean(x)` on its own (without an intersecting positive term) matches a huge surface — always pair a negation with a positive designator. - `*` is greedy across the whole name segment; there's no `?` single-char or character-class support. - Combining `bean()` with `within()`/`execution()` is common; if they disagree (e.g. name says match but type says no), the AND simply yields no match.

  • Does bean() support regular expressions?
    No. Only the * glob wildcard is supported inside the name; there is no regex, no ? single-char, and no character classes.
  • What's the risk of a pointcut that is just !bean(foo)?
    A lone negation matches an enormous surface (every advised join point except foo's), so advice fires almost everywhere. Always intersect a negation with a positive designator like execution(...) or bean(*Service).

saying these in an interview costs you the question

  • Assuming bean() takes a regex
  • Using !bean(x) alone and expecting narrow matching
  • Thinking bean(*Service) matches by class name so a renamed bean still matches

context