How do aspects work with components for AOP?
← Classes and OOP · Ref: Q114
EK9 supports Aspect-Oriented Programming through the Aspect base class and application registration. Aspects wrap component calls with before and after advice.
ASPECT CLASS
Create an aspect by extending the built-in Aspect class:
LoggingAspect extends Aspect override beforeAdvice() -> joinPoint as JoinPoint <- rtn as PreparedMetaData: PreparedMetaData(joinPoint) override afterAdvice() -> preparedMetaData as PreparedMetaData
BEFORE AND AFTER ADVICE
beforeAdvice() runs before each method call. afterAdvice() runs after. The JoinPoint provides the component name and method name.
JOINPOINT
The JoinPoint parameter gives execution context:
joinPoint.componentName() the component being called
joinPoint.methodName() the method being called
REGISTERING WITH ASPECTS
Use 'with aspect of' in application registration:
register Solution1() as Config with aspect of LoggingAspect(), TimerAspect()
Multiple aspects chain in declaration order.
CHAINING MULTIPLE ASPECTS
Multiple aspects wrap in order: the first listed runs outermost. Each aspect's beforeAdvice runs before the next, and afterAdvice runs in reverse order.
See Q111 for components. See Q112 for services. See Q102 for 'as open'. See Q119 for constructs overview. See Q227 for compile-time DI validation.
See Q337 for transaction aspects.
Example
defines module qa.oop.aspects defines component Config as abstract getValue() as abstract <- rtn as String? default operator ? ProductionConfig extends Config override getValue() <- rtn as String: "production-database" default operator ? defines class SimpleAspect extends Aspect label <- String() SimpleAspect() -> label as String this.label: label override beforeAdvice() -> joinPoint as JoinPoint <- rtn as PreparedMetaData: PreparedMetaData(joinPoint) Stdout().println(`${label} BEFORE: ${joinPoint.componentName()}.${joinPoint.methodName()}`) override afterAdvice() -> preparedMetaData as PreparedMetaData joinPoint <- preparedMetaData.joinPoint() Stdout().println(`${label} AFTER: ${joinPoint.componentName()}.${joinPoint.methodName()}`) default operator ? defines application AspectApp register ProductionConfig() as Config with aspect of SimpleAspect("LOG") defines program AspectsDemo() with application of AspectApp stdout <- Stdout() // === INJECTION with aspects applied === config as Config! stdout.println(`Value: ${config.getValue()}`)
Common mistakes
E05120 — When implementing Aspect's abstract methods beforeAdvice() and afterAdvice(), the 'override' keyword is mandatory. Omitting it triggers E05120. See ek9 -h E05120 for details.
Incorrect:
beforeAdvice()
Correct:
override beforeAdvice()
E05120 — ProductionConfig must use 'override' when implementing Config's abstract method getValue(). See ek9 -h E05120 for details.
Incorrect:
getValue()
Correct:
override getValue()
E50001 — The aspect type used in 'with aspect of' must be a defined type. If the type does not exist, E50001 is triggered — not resolved. Check spelling and ensure the aspect class is defined. See ek9 -h E50001 for details.
Incorrect:
register ProductionConfig() as Config with aspect of NonExistentAspect()
Correct:
register ProductionConfig() as Config with aspect of SimpleAspect("LOG")
E50020 — Aspect is a built-in class, not a component. Defining an aspect subclass inside 'defines component' triggers E50020 because components cannot extend classes — incompatible genus. Aspect subclasses belong in 'defines class'. See ek9 -h E50020 for details.
Incorrect:
defines component
Correct:
defines class
E50080 — Config is declared 'as abstract' and cannot be instantiated directly. The register statement must use a concrete implementation (ProductionConfig), not the abstract base type. See ek9 -h E50080 for details.
Incorrect:
register Config() as Config
Correct:
register ProductionConfig() as Config
Other ways to ask this
- How does aspect-oriented programming work in EK9?
- How do I add logging or timing to components in EK9?
- What is the Aspect class in EK9?
Coming from another language?
Java: Spring AOP with @Before/@After annotations and proxy-based weaving, AspectJ for compile-time weaving. Python: decorators for simple AOP, no JoinPoint concept built-in. Rust: no built-in AOP, procedural macros for compile-time code generation. Go: no built-in AOP, middleware pattern for HTTP, manual wrapping. Kotlin: Spring AOP same as Java, no language-level AOP. EK9: language-level Aspect base class, beforeAdvice/afterAdvice methods, JoinPoint for context, 'register with aspect of' syntax in application definitions.
Keywords: after, aspect, cross-cutting, component, register, weave, logging, aop, advice, before, joinpoint, timing, object-oriented