skip to content

How do you reference a named pointcut declared in a DIFFERENT aspect class, and what role does the pointcut method's visibility play?

level: seniorimportance: should knowfreq 40%

answer

  1. FQN: Class.pointcutName()
  2. public = shareable, private = same class
  3. holder can be advice-free declaration class
  4. SystemArchitecture / CommonPointcuts pattern
  5. compose imported + local

basics

~20 s

Use the fully-qualified reference: ClassName.pointcutName() (or the full package path). The pointcut method must be visible enough — make it public (or protected/package-private) so other aspects can reference it; a private @Pointcut is only usable inside its own class.

solid answer

~40 s

A named pointcut in another aspect is referenced by its enclosing type plus method name, e.g. CommonPointcuts.serviceLayer() or the fully-qualified com.app.aop.CommonPointcuts.serviceLayer(). This is the standard pattern for a shared 'pointcut library': one @Aspect (or plain class) holds public @Pointcut definitions, and every other aspect references them. The pointcut method's Java access modifier governs who can reference it, exactly like normal method visibility: private = same class only; package-private = same package; protected = subclasses; public = anywhere. So library pointcuts you intend to share must be public. The holder doesn't even need advice — it can be a pure declaration class. This centralizes 'what is a service method / web request / repository call' so teams don't drift into inconsistent expressions.

code

java · 28 lines
java
package com.app.aop;

// Pure declaration library — no advice needed
public class CommonPointcuts {
    @Pointcut("within(com.app.service..*)")
    public void inServiceLayer() {}          // public => referenceable anywhere

    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void transactional() {}

    @Pointcut("execution(* toString(..))")
    private void internalHelper() {}         // private => only usable in this class
}

package com.app.metrics;

import org.aspectj.lang.ProceedingJoinPoint;

@org.aspectj.lang.annotation.Aspect
@org.springframework.stereotype.Component
public class TxTimingAspect {
    // Fully-qualified cross-class reference, composed with && 
    @org.aspectj.lang.annotation.Around(
        "com.app.aop.CommonPointcuts.inServiceLayer() && com.app.aop.CommonPointcuts.transactional()")
    public Object time(ProceedingJoinPoint pjp) throws Throwable {
        return pjp.proceed();
    }
}

go deeper

for a junior

Aware that pointcuts can live in another class and be referenced by name.

for a middle

Can write Class.pointcut() references and knows public is needed to share.

for a senior

Explains the full visibility ladder, advice-free holder class, and composition across classes.

for a principal

Designs a governed CommonPointcuts library as the single source of truth for cross-cutting selections.

**The pattern: a shared pointcut library.** Large codebases collect a set of well-known selections — 'anything in the service layer', 'any Spring @RestController method', 'any repository call'. Rather than redefine these in every aspect, you declare them once in a dedicated class of `@Pointcut` methods and reference them everywhere. This is the canonical AspectJ 'SystemArchitecture' pattern, and it works in Spring AOP too. **How cross-aspect references are written.** From outside the declaring class, you must qualify the pointcut name with the declaring type: - Same package: `CommonPointcuts.serviceLayer()`. - Different package: the fully-qualified name `com.app.aop.CommonPointcuts.serviceLayer()`. Inside the declaring class you use the bare name `serviceLayer()`. ```java public class CommonPointcuts { @Pointcut("within(com.app.service..*)") public void inServiceLayer() {} @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)") public void getMappings() {} } @Aspect @Component public class MetricsAspect { @Around("com.app.aop.CommonPointcuts.inServiceLayer()") public Object time(ProceedingJoinPoint pjp) throws Throwable { return pjp.proceed(); } } ``` **Visibility rules — the key gotcha.** The `@Pointcut` method's Java access modifier controls reference visibility, mirroring normal method access: - `private` — referenceable only within the same aspect class. Use for internal helpers. - package-private (default) — same package. - `protected` — same package + subclasses. - `public` — anywhere. **Library/shared pointcuts must be public.** A common mistake is declaring a shared pointcut `private` (or letting it default) and then getting an 'unresolved pointcut' / cannot-reference error from another aspect. **The holder need not be an aspect.** The class holding shared `@Pointcut` methods does **not** need `@Aspect` or any advice — it can be a plain class of pure declarations (though people often still annotate it `@Aspect`). It also does not need to be a Spring bean if it contains no advice; it's just a namespace of expressions. That said, marking it `@Aspect` is common and harmless. **Composition across aspects.** You can compose imported pointcuts with local ones: `@Pointcut("com.app.aop.CommonPointcuts.inServiceLayer() && !localExclusions()")`. Fully-qualified references combine with `&& || !` like any other operand. **Parameter binding across classes.** If the shared pointcut declares parameters for binding (e.g. `args()`), the referencing advice threads those parameters through as usual; visibility still must permit the reference. **Gotchas.** - Forgetting `public` on a shared pointcut → resolution failure. - Using the simple class name across packages without the full path → won't resolve; qualify fully. - Assuming the library class must have advice or be a proxied bean — it doesn't for pure declarations. **When to use.** Whenever more than one aspect (or one aspect used widely) needs the same selection. Centralizing pointcuts is a maintainability multiplier: change 'service layer' definition once, everywhere follows.

  • Does the class that holds shared @Pointcut methods need to be an @Aspect or a Spring bean?
    Not for pure declarations. A class containing only @Pointcut methods (no advice) is just a namespace of expressions; it needs neither @Aspect nor to be a managed bean to be referenced by fully-qualified name. It's common to still annotate it @Aspect, and it does need to be a bean only if it also carries advice that must run.
  • You reference com.app.CommonPointcuts.serviceLayer() from another aspect and get a resolution error — what's the most likely cause?
    The pointcut method isn't visible: it's private (or package-private and you're in a different package). Shared pointcuts must be public. Also verify the fully-qualified class path is correct.

saying these in an interview costs you the question

  • Claiming a shared pointcut can be private and still referenced elsewhere
  • Thinking you can only reference pointcuts within the same aspect
  • Believing the declaration class must carry advice or be a proxied bean

context