How do you reference a named pointcut declared in a DIFFERENT aspect class, and what role does the pointcut method's visibility play?
answer
- FQN: Class.pointcutName()
- public = shareable, private = same class
- holder can be advice-free declaration class
- SystemArchitecture / CommonPointcuts pattern
- compose imported + local
basics
~20 sUse 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 sA 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 linespackage 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
Aware that pointcuts can live in another class and be referenced by name.
Can write Class.pointcut() references and knows public is needed to share.
Explains the full visibility ladder, advice-free holder class, and composition across classes.
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