ArchitectMind
  1. Home
  2. Tutorials
  3. Book 4 · Spring & Spring Boot
  4. Volume II
  5. Aspect-Oriented Programming
Book 4 · Volume II — Spring AOP, Proxies, Events & Transactions · Topic 1.3

Aspect-Oriented Programming

Aspect, join point, pointcut, advice and weaving — the vocabulary of modular cross-cutting behaviour

9 min readStage 2 · Frameworks & design8 interview questions
Chapter
Chapter 1 — Cross-Cutting Concerns
Prerequisites
Topics 1.1–1.2
You will be able to
Define and apply the five AOP concepts, map them to Spring and AspectJ constructs, and choose a weaving strategy
Covers
Aspect · Join Point · Pointcut · Advice · Weaving
On this page
  1. 1. Concept / Definition
  2. 2. Why It Exists
  3. 3. Core Concepts
  4. 4. How It Works Internally
  5. 4A. Deep Dive — Spring AOP or Full AspectJ?
  6. 5. APIs / Features / Syntax
  7. 6. Practical Examples
  8. 7. Common Problems & Mistakes
  9. 8. Performance & Production Considerations
  10. 9. Architecture & Design Considerations
  11. 10. Interview Questions & Answers

1Concept / Definition

Aspect-Oriented Programming (AOP) is a programming paradigm that modularises cross-cutting concerns. It complements OOP: classes modularise the domain, aspects modularise policies that cut across classes.

TermDefinitionSpring / AspectJ construct
AspectA module encapsulating a cross-cutting concern: advice + pointcuts@Aspect class
Join pointA well-defined point in program execution where behaviour can be addedMethod execution (Spring AOP); also calls, field access, constructors (AspectJ)
PointcutA predicate that selects join points@Pointcut("execution(* com.acme..*Service.*(..))")
AdviceAction taken at selected join points, and when@Before, @After, @AfterReturning, @AfterThrowing, @Around
WeavingLinking aspects with target code to create advised objectsRuntime proxies (Spring); compile/load-time (AspectJ)
Table 1 — The five core AOP concepts
The AOP vocabulary on one picture
Figure 1 — The AOP vocabulary on one picture

Related terms: target object (the object being advised), AOP proxy (the object created to implement the aspect contracts), advisor (Spring: one pointcut + one advice), introduction (adding interfaces to a type).

2Why It Exists

As Topic 1.2 showed, OOP lacks a way for a concern to say where it applies. AOP, developed at Xerox PARC (Gregor Kiczales and colleagues, 1997) and implemented as AspectJ (2001), added that capability as a language extension. Spring adopted a pragmatic subset in 2004: proxy-based method interception, later using AspectJ's annotation style and pointcut language (Spring 2.0) while keeping runtime weaving so that no special compiler is required.

3Core Concepts

3.1 Aspect

JAVA
@Aspect
@Component
class PerformanceAspect {
    private final MeterRegistry meters;
    PerformanceAspect(MeterRegistry meters) { this.meters = meters; }
 
    @Pointcut("within(com.acme..service..*) && execution(public * *(..))")  // WHERE
    void publicServiceMethods() { }
 
    @Around("publicServiceMethods()")  // WHAT + WHEN
    Object time(ProceedingJoinPoint pjp) throws Throwable {
        var sample = Timer.start(meters);
        try { return pjp.proceed(); }
        finally {
            sample.stop(meters.timer("service.calls",
                    "method", pjp.getSignature().toShortString()));
        }
    }
}

3.2 Join point

Join point kindAspectJSpring AOP
Method executionYesYes (only kind)
Method call (at the caller)YesNo
Constructor execution/callYesNo
Field get/setYesNo
Static initialisationYesNo
Exception handler executionYesNo
Table 2 — Join points by implementation

3.3 Pointcut

A pointcut is a boolean expression over join points: execution(* com.acme..*Service.*(..)) && @annotation(audited). Pointcuts can be named and combined with &&, ||, !. Details in Topic 2.3.

3.4 Advice

What executes at an advised join point
Figure 2 — What executes at an advised join point
AdviceRuns
BeforeBefore the join point
After returningAfter normal completion
After throwingAfter an exception
After (finally)After either outcome
AroundSurrounds the join point; decides whether/how it proceeds
Table 3 — Advice kinds (Topic 2.2 covers them in depth)

3.5 Weaving

Weaving options
Figure 3 — Weaving options
WeavingHowProsCons
Compile-timeajc compilerAll join points; no runtime overhead for weavingSpecial build
Post-compile (binary)Weave existing class files/JARsAdvise third-party codeBuild step
Load-time (LTW)Java agent / Spring @EnableLoadTimeWeavingNo special compiler; full AspectJJVM agent, class-loader setup
Runtime (proxies)Spring AOPZero setup; per-beanMethod execution only; proxy limitations
Table 4 — Weaving strategies

4How It Works Internally

In Spring AOP, weaving happens when a bean is created. The auto-proxy creator (a BeanPostProcessor) collects advisors — from @Aspect beans, @Transactional infrastructure, method security and others — tests each bean's class and methods against their pointcuts, and wraps matching beans in a proxy. At call time the proxy builds an interceptor chain for the invoked method (cached per method) and executes it.

AOP conceptSpring runtime object
Aspect@Aspect bean → several InstantiationModelAwarePointcutAdvisors
PointcutAspectJExpressionPointcut (uses AspectJ's parser/matcher)
AdviceAspectJAroundAdvice, AspectJMethodBeforeAdvice, … adapted to MethodInterceptor
Join pointMethodInvocation / ProceedingJoinPoint
WeavingAbstractAutoProxyCreator.wrapIfNecessary → ProxyFactory
Table 5 — AOP concepts as Spring runtime objects

4ADeep Dive — Spring AOP or Full AspectJ?

Decision factorSpring AOP is enoughConsider AspectJ
TargetsSpring beansDomain objects created with new, JPA entities, third-party classes
Join pointsPublic (or class-proxy-visible) method executionsField access, constructors, calls, private methods
Self-invocationAcceptable to restructureMust be advised
PerformanceMicrosecond overhead fineVery hot, fine-grained methods
Build/deployKeep simpleTeam can manage ajc or an agent
Table 6 — Choosing an AOP implementation

Spring can use AspectJ weaving for its own infrastructure too: @EnableTransactionManagement(mode = AdviceMode.ASPECTJ) and @EnableCaching(mode = ASPECTJ) switch from proxies to AspectJ-woven aspects, which removes self-invocation and visibility limits at the cost of weaving setup.

XML
<!-- Load-time weaving: META-INF/aop.xml -->
<aspectj>
  <weaver options="-Xlint:ignore">
    <include within="com.acme..*"/>
  </weaver>
  <aspects>
    <aspect name="com.acme.audit.DomainAuditAspect"/>
  </aspects>
</aspectj>

5APIs / Features / Syntax

APIPurpose
@Aspect, @PointcutDeclare aspects and named pointcuts
@Before, @After, @AfterReturning, @AfterThrowing, @AroundAdvice
JoinPoint, ProceedingJoinPointJoin point access
@EnableAspectJAutoProxyEnable @Aspect processing (Boot auto-configures)
@EnableLoadTimeWeaving, aop.xmlAspectJ load-time weaving
ProxyFactory, Advisor, MethodInterceptorProgrammatic Spring AOP
Table 7 — AOP APIs

6Practical Examples

6.1 Programmatic AOP without annotations

JAVA
var factory = new ProxyFactory(new PriceServiceImpl());
factory.addAdvice((MethodInterceptor) inv -> {
    log.debug("-> {}", inv.getMethod().getName());
    return inv.proceed();
});
PriceService proxied = (PriceService) factory.getProxy();
proxied.price("SKU-1");      // logs, then calls the target

6.2 Aspect with annotation-based pointcut

JAVA
@Aspect @Component
class ReadOnlyGuard {
    @Before("@annotation(com.acme.ReadOnlyOperation) && args(.., cmd)")
    void guard(Object cmd) {
        if (Maintenance.isOn()) throw new MaintenanceModeException();
    }
}

6.3 Introductions — adding an interface to existing beans

JAVA
public interface Versioned { String version(); }
public class DefaultVersioned implements Versioned {
    public String version() { return "v1"; }
}
 
@Aspect @Component
class VersioningIntroduction {
    // every matching bean now also implements Versioned
    @DeclareParents(value = "com.acme.api..*Controller+",
                    defaultImpl = DefaultVersioned.class)
    public static Versioned mixin;
}
// ((Versioned) ctx.getBean(OrderController.class)).version()  → "v1"

Introductions are the least used AOP feature; they are shown here to complete the vocabulary. Prefer ordinary interfaces unless you must retrofit behaviour onto classes you cannot change.

6.4 Testing an aspect in isolation

JAVA
@Test
void timesServiceCalls() {
    var registry = new SimpleMeterRegistry();
    var factory = new AspectJProxyFactory(new PriceServiceImpl());
    factory.addAspect(new PerformanceAspect(registry));
    PriceService proxy = factory.getProxy();
 
    proxy.price("SKU-1");
 
    assertThat(registry.find("service.calls").timer().count()).isEqualTo(1);
}

AspectJProxyFactory applies an @Aspect instance to a target without starting a Spring context — the fastest way to test pointcut matching and advice behaviour together.

6.5 Mapping the vocabulary to familiar annotations

Annotation you already useJoin pointPointcutAdvice kind
@TransactionalMethod executionMethods/classes annotated @TransactionalAround
@CacheableMethod executionAnnotated methodsAround (may skip the call)
@PreAuthorizeMethod executionAnnotated methodsBefore (throws to deny)
@AsyncMethod executionAnnotated methodsAround (submits to executor)
@Timed / @ObservedMethod executionAnnotated methodsAround
Table 8 — Framework features expressed in AOP terms

7Common Problems & Mistakes

  • Expecting Spring AOP to advise non-bean objects. Only container-managed proxies are advised.
  • Pointcuts that match too much. execution(* *(..)) advises every bean method, including framework beans.
  • Confusing call and execution join points. Spring advises execution in the target via the proxy.
  • Putting business rules into aspects. Aspects should implement policies.
  • Ignoring advice ordering. Several aspects on one method need explicit @Order.

Most of these mistakes show up as an aspect that silently does nothing, or does far too much. When advice never runs, check three things in order: that the target is a Spring bean obtained from the container rather than created with new, that the call enters through the proxy rather than via this, and that the method is neither final nor private, because a CGLIB subclass cannot override either. Logging the bean's class at start-up, or calling AopUtils.isAopProxy, confirms whether a proxy exists at all. Over-broad pointcuts fail differently: execution(* *(..)) also matches framework and configuration beans, which slows start-up, creates early proxies that trigger 'not eligible for auto-proxying' log messages and can even cause circular-reference errors. A further trap is throwing a checked exception from @Around advice that the target method does not declare; the proxy then wraps it in an UndeclaredThrowableException that callers never expect. Finally, aspects without an explicit order run in an undefined sequence, so give each custom aspect an @Order relative to the transaction and security advisors.

8Performance & Production Considerations

ConcernGuidance
Proxy overheadOne interceptor chain per call; negligible for service methods
Pointcut matchingDone at proxy creation and cached per method — keep pointcuts specific to limit start-up work
AspectJ weavingNo proxy hop; LTW adds class-loading time
DebuggabilityStack traces show interceptor frames; name aspects clearly
Table 9 — Production guidance

9Architecture & Design Considerations

  • AOP as a second modularity axis complements, not replaces, good domain design.
  • Annotation-driven pointcuts are the most maintainable: @annotation(Audited) is explicit at the target; package-wide execution pointcuts are powerful but invisible.
  • Aspects are part of the architecture. Document them and include them in reviews.
  • Prefer framework-provided aspects (transactions, caching, security, observation) before writing custom ones.

10Interview Questions & Answers

Q1BasicConcept

What is AOP?

Aspect-Oriented Programming is a paradigm for modularising cross-cutting concerns: behaviour such as logging, transactions, security checks, metrics and auditing that would otherwise be repeated across many classes. OOP modularises the domain into classes, but a policy like 'every public service method is timed' has no natural home there, so the code ends up tangled with business logic and scattered across the codebase. AOP lets you write that policy once as an aspect, declare where it applies with a pointcut, and let the framework attach it. In Spring it is not an exotic extra: @Transactional, @Cacheable, @PreAuthorize and @Async are all implemented with AOP proxies, so every Spring developer already relies on it daily.

Q2BasicConcept

Define join point, pointcut and advice.

A join point is a well-defined point in program execution where extra behaviour could be attached. AspectJ supports many kinds, such as method calls, field access and constructor execution, but in Spring AOP a join point is always a method execution on a Spring bean. A pointcut is a predicate that selects a subset of join points, written in AspectJ's expression language, for example execution(* com.acme..*Service.*(..)) or @annotation(Audited). Advice is the code that runs at the selected join points, together with when it runs: before, after returning, after throwing, after in the finally sense, or around. In short, join points are the candidates, the pointcut chooses where, the advice says what and when.

Q3IntermediateConcept

What is weaving and which kind does Spring AOP use?

Weaving is the process of linking aspects with target code so that advice actually runs at the matched join points. AspectJ can weave at compile time with the ajc compiler, post-compile into existing class files and JARs, or at load time through a Java agent that rewrites classes as they are loaded. Spring AOP weaves at runtime and never modifies the bytecode of your classes: when a bean is created, the auto-proxy creator wraps it in a JDK dynamic proxy or a CGLIB subclass, and that proxy runs the advice chain. This is why Spring AOP needs no special build step or agent, and also why it only affects calls that go through the proxy.

Q4IntermediateTricky

What join points does Spring AOP support?

Only method execution join points, and only on Spring-managed beans when the call passes through the proxy. With JDK dynamic proxies, used when proxying interfaces, that means interface methods. With CGLIB class proxies, which Boot uses by default, public and protected methods can be advised, and even package-visible ones if necessary, but final, private and static methods cannot, because the generated subclass cannot override them. Constructors, field reads and writes, static initialisers and calls made inside the same object through this are invisible to Spring AOP. If a requirement needs any of those, for example advising JPA entities or self-invocations, you need AspectJ compile-time or load-time weaving instead of proxies.

Q5Senior EngineerInternals

What is an advisor in Spring?

An advisor is Spring's own building block that pairs exactly one pointcut with exactly one advice; AspectJ has no equivalent term. It is what the auto-proxy creator actually works with: for each bean it collects every Advisor in the context, asks each pointcut whether it matches the bean's class and methods, and builds a proxy from the matching advisors. An @Aspect class is not used directly; ReflectiveAspectJAdvisorFactory turns each advice method into its own advisor, so an aspect with three advice methods becomes three advisors. Infrastructure contributes advisors too, such as BeanFactoryTransactionAttributeSourceAdvisor for @Transactional and the method-security advisors for @PreAuthorize, which is why their ordering can be controlled like any aspect.

Q6Senior EngineerTrade-off

When would you choose AspectJ weaving over Spring AOP?

I choose AspectJ only when a concrete requirement exceeds what proxies can do. Typical triggers are advising objects that Spring does not create, such as JPA entities or domain objects built with new, needing non-method join points like field access or constructors, advising private methods, or requiring self-invocations to be intercepted, for example a @Transactional method called from another method in the same class. Very hot, fine-grained methods where the proxy hop is measurable are another reason. The price is a special build step with ajc, or a load-time weaving agent and class-loader setup, plus tooling and debugging that fewer developers know. Before switching, I always check whether splitting the bean solves the problem.

Q7Technical ArchitectDesign

How do you keep custom aspects maintainable?

I treat each custom aspect as a small platform feature with an owner. The pointcut should be explicit at the target, ideally a marker annotation such as @Audited, so a reader of the method can see that behaviour is attached; package-wide execution pointcuts are powerful but invisible in code review. Advice stays thin and delegates to an ordinary service bean that can be unit tested. Ordering relative to transactions and security is declared with @Order and documented, because whether auditing runs inside or outside the transaction changes behaviour on rollback. I test pointcut matching and advice together with AspectJProxyFactory, and add ArchUnit rules that stop business rules creeping into aspects over time.

Q8Solution ArchitectDesign

What role does AOP play in an enterprise platform?

AOP is the mechanism through which platform policies reach application code without every team reimplementing them. Transactions, method security, caching, observation with @Observed, the resilience annotations for retry and concurrency limits added in Framework 7, and audit trails are all applied as advice around business methods. That gives a platform team a single place to change behaviour: a new tracing attribute or audit field is added once in an aspect or starter and appears across every service after an upgrade. The architectural risk is invisibility, so I would favour framework-provided aspects, require explicit annotations for custom policies, document ordering, and keep business decisions out of aspects so domain logic stays readable.

Newsletter

Get new tutorials every week

New ArchitectMind tutorials and interview questions, once a week. No spam, unsubscribe anytime.

Almost done! Check your inbox and click the confirmation link to complete your subscription.
Keep going in Book 4

Spring & Spring Boot

Volume I · Topic 1.1

Why Spring Exists

Spring Core, IoC & Dependency Injection

Volume I · Topic 1.2

Spring Framework Architecture

Spring Core, IoC & Dependency Injection

Volume I · Topic 1.3

Spring Modules

Spring Core, IoC & Dependency Injection

Volume II · Topic 1.1

Cross-Cutting Concerns

Spring AOP, Proxies, Events & Transactions

Volume II · Topic 1.2

Why Cross-Cutting Concerns Are Difficult

Spring AOP, Proxies, Events & Transactions

Volume III · Topic 1.1

Why Spring Boot Exists

Spring Boot, Configuration & Application Lifecycle

Volume III · Topic 1.2

Spring Boot Architecture

Spring Boot, Configuration & Application Lifecycle

Volume III · Topic 1.3

Spring Boot vs Spring Framework

Spring Boot, Configuration & Application Lifecycle

Volume IV · Topic 1.1

MVC

Spring MVC, REST & Web Applications

Volume IV · Topic 1.2

DispatcherServlet

Spring MVC, REST & Web Applications

Volume IV · Topic 1.3

MVC Request Lifecycle

Spring MVC, REST & Web Applications

Volume V · Topic 1.1

Repository Abstraction

Spring Data, JPA & Persistence

Volume V · Topic 1.2

Spring Data Architecture

Spring Data, JPA & Persistence

Volume V · Topic 1.3

Repository Types

Spring Data, JPA & Persistence

Volume VI · Topic 1.1

Security Architecture

Spring Security, OAuth2 & Identity

Volume VI · Topic 1.2

Security Filter Chain

Spring Security, OAuth2 & Identity

Volume VI · Topic 1.3

Security Context

Spring Security, OAuth2 & Identity

Volume VII · Topic 1.1

Enterprise Integration

Spring Integration, Testing & Cloud-Native Development

Volume VII · Topic 1.2

Integration Patterns

Spring Integration, Testing & Cloud-Native Development

Volume VII · Topic 1.3

Messaging Systems

Spring Integration, Testing & Cloud-Native Development