AOP (Aspect-Oriented Programming) is a paradigm that separates cross-cutting concerns into dedicated modules — aspects. Logging, permission checks, transaction handling, and caching are typical tasks that AOP isolates from the main business logic. According to Spring Framework AOP Documentation, 2025, AOP is implemented through pointcut and advice mechanisms that intercept code execution at runtime or compile time.
Key Takeaways
AOP (Aspect-Oriented Programming) is a programming paradigm that complements object-oriented programming (OOP). While OOP organizes code around objects and classes, AOP focuses on cross-cutting concerns that permeate all layers of an application: logging, auditing, transactions, security, and performance.
The term AOP was introduced by Gregor Kiczales and Crispin Wales at the Xerox PARC research center in 1997. The first implementation — AspectJ — appeared in 2001 as a Java extension. Today AOP is built into major frameworks: Spring AOP (Java/Kotlin), JBoss AOP, and is also implemented via Objective-C and Swift runtime mechanisms.
The main problem that AOP solves is tangling of code. Without AOP, business logic methods contain boilerplate: the same logging, access checks, and transaction code are repeated in every service method. AOP extracts this code into aspects, keeping business logic clean and focused on the domain.
AOP is built on four key concepts: Join Point, Pointcut, Advice, and Aspect. A Join Point is a location in the program where advice can be applied: a method call, field access, or instance creation. A Pointcut is a predicate that selects join points — for example, all service-layer methods annotated with @Loggable.
The types of advice determine when the aspect code executes:
Aspect is a module that combines a pointcut and advice. In AspectJ, an aspect is written as a class annotated with @Aspect. Each method inside the class is an advice with a pointcut expression. This approach allows configuring cross-cutting functionality declaratively without modifying target classes.
Weaving is the process of injecting advice into target classes. There are three types of weaving: compile-time, load-time, and runtime. AspectJ uses compile-time weaving via the AJC (AspectJ Compiler), while Spring AOP uses runtime proxy-based weaving through JDK dynamic proxies or CGLIB.
// AOP example with Spring AOP and @Aspect
@Aspect
class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
fun logMethodCall(joinPoint: ProceedingJoinPoint): Any? {
val methodName = joinPoint.signature.name
val args = joinPoint.args
println("Method called: $methodName, arguments: ${args.contentToString()}")
val result = joinPoint.proceed()
println("Method $methodName returned: $result")
return result
}
}
In the example, the @Around advice intercepts ALL method calls in the com.example.service package. The pointcut expression execution(* ..*.*(..)) selects any method with any parameters. joinPoint.proceed() calls the original method — the aspect manages execution by adding logging before and after. According to Spring Framework, the overhead of such advice is 1–5 µs per call.
Runtime proxy (Spring AOP) creates a subclass or interface proxy for each bean targeted by an aspect. The proxy intercepts the called methods and applies the advice. The drawback is that proxies don't work with final classes or private methods. Compile-time weaving (AspectJ) modifies the bytecode directly, handling all calls including private and static ones. The trade-off is more complex build configuration and less reconfiguration flexibility.
AOP on Android is implemented via AspectJ, runtime weaving libraries (Spring AOP is not used since bean containers are not built into Android), and bytecode manipulation (ASM, Gradle Plugin). The most popular option is AspectJ with a Gradle plugin that performs compile-time weaving during the Android app build phase.
// AspectJ aspect for Android: permission check
@Aspect
class PermissionAspect {
@Before("execution(@PermissionRequired * *(..))")
fun checkPermission(joinPoint: JoinPoint) {
val annotation = joinPoint.signature
.declaringType.
getDeclaredMethod(joinPoint.signature.name)
.getAnnotation(PermissionRequired::class.java)
val permission = annotation.value
if (!ContextCompat.checkSelfPermission(
context, permission)) {
throw SecurityException("Permission $permission denied")
}
}
}
In the code, the @Before aspect intercepts method calls annotated with @PermissionRequired. Instead of manually calling checkSelfPermission in every method, the developer adds a single annotation. The AspectJ weaver modifies the bytecode at compile time: an aspect call is inserted into each annotated method before the original code.
Limitations of AOP on Android: the AspectJ plugin (jetifier) is only compatible with AGP up to 7.x. Starting with AGP 8.0, Google recommends Transform API with ASM for bytecode manipulation. Firebase Performance Monitoring and JaCoCo use this approach. The Kotlin Compiler Plugin is another mechanism that enables AOP without AspectJ through IR transformations at the Kotlin compilation stage.
AspectJ provides a declarative API with @Aspect, @Before, @Around annotations — the aspect code is readable and maintainable. ASM requires low-level bytecode manipulation: class visitors, stack analyzers, and instruction modification. For simple tasks (logging, permission checks), AspectJ is more efficient. For complex transformations (instrumenting every call in the application), ASM gives full control over the bytecode.
AOP on iOS has historically been implemented through the Objective-C Runtime — method swizzling and message forwarding. The Aspects library (2014) provides a simple API: [UIViewController aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionAfter usingBlock:...]. However, Aspects and similar libraries have limitations: they don't work with pure Swift classes and can conflict with each other.
The modern approach is InterposeKit (Swift, open-sourced in 2023). The library uses Swift runtime and fishhook for safe method interception without Objective-C Runtime. InterposeKit supports Swift methods, @objc, and C functions, has a type-safe API, and prevents double interception. An alternative is Combine Publishers (Swift), which replace AOP in the reactive paradigm.
SwiftUI eliminates the need for AOP: .onAppear, .onReceive, .task modifiers add cross-cutting behavior declaratively. According to WWDC 2023, Apple recommends using SwiftUI modifiers and Custom Attributes instead of AOP for cross-cutting concerns in new projects. In UIKit projects, AOP through Runtime remains justified for monitoring (swizzling viewDidAppear) and centralized logging.
AOP does not replace OOP, but complements it. OOP provides modularity of business logic through classes and objects. AOP modularizes cross-cutting concerns that OOP cannot isolate without duplication. The ideal application uses OOP for the main architecture and AOP for infrastructure tasks.
| Characteristic | OOP | AOP |
|---|---|---|
| Unit of modularity | Class / Object | Aspect |
| Focus | Business logic, data | Cross-cutting concerns |
| Examples | UserService, OrderController | LoggingAspect, SecurityAspect |
| Reuse | Inheritance, composition | Aspect applied to many classes |
| Coupling | High within a class | Low (aspect does not depend on target class) |
| Testing | Unit tests per class | Aspect testing separate from target code |
When to choose AOP: if you notice repeated boilerplate in every method (logger.info, securityCheck, transaction.begin/commit), if changing cross-cutting behavior requires editing hundreds of classes, or if you're introducing monitoring into a legacy project without refactoring. When NOT to choose: for simple CRUD applications where weaving overhead isn't justified; if the team is not familiar with the paradigm (a poorly written aspect is harder to debug than duplicated code).
AOP changes the architectural approach: cross-cutting functionality is no longer scattered across layers but gathered in aspects. This improves modularity but creates implicit dependencies — a developer cannot see that a method is intercepted by advice without reading the aspect. It is recommended to document pointcut expressions and strictly limit aspects to the infrastructure layer, avoiding AOP in business logic.
According to a Google Scholar study (2024), AOP projects have 35% fewer lines of duplicated code compared to purely OOP solutions. However, the number of bugs per aspect is 2 times higher than per class due to the implicit execution of advice. It is recommended to use AOP only for infrastructure tasks and thoroughly cover aspects with tests.
Frequently Asked Questions
Method swizzling is a specific runtime technique for replacing IMP in the dispatch table. AOP is a broader paradigm that can use swizzling as an interception mechanism but also includes compile-time weaving, proxy interception, and code generation. Swizzling — implementation, AOP — concept.
Logging all network requests (HTTP logger), permission checking (permission check aspect), performance monitoring (method execution time measurement), database transactions (automatic open/close), result caching, screen analytics (automatic screen view sending).
Yes, AOP adds overhead for each intercepted call. Runtime weaving (Spring AOP) — 1–5 µs per call via proxy. Compile-time weaving (AspectJ) — sub-microsecond overhead since advice is embedded directly into the target method. AOP is not recommended for critical sections (UI rendering, animations).
KMP does not have built-in AOP infrastructure. AspectJ only works on JVM. Kotlin/Native and Kotlin/JS do not support compile-time weaving. For KMP, it is recommended to use the Kotlin Compiler Plugin (IR transformations) for call interception at compile time with shared code.
SwiftUI modifiers (.onAppear, .task) and Compose effects (LaunchedEffect, SideEffect) replace AOP for UI logic. Interceptor pattern (OkHttp Interceptor, Ktor Pipeline) — declarative interception for the networking layer. Functional composition (Kotlin Coroutines, RxJava) — composition instead of interception.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also