What is the EK9 equivalent of Spring @Component and @Service?
← Dependency Injection · Ref: Q325
EK9 replaces Spring's @Component and @Service with the 'defines component' construct. Components in EK9 are types that can be registered in applications and injected into programs.
SPRING ANNOTATIONS VS EK9 CONSTRUCTS
Spring uses @Component/@Service annotations on classes that are auto-scanned:
@Service public class OrderService { ... }
EK9 uses the 'defines component' section to declare injectable types:
defines component OrderService as abstract ... DefaultOrderService is OrderService ...
NO AUTO-SCANNING
Spring scans the classpath for annotated classes. EK9 requires explicit registration in the application definition. This is intentional: explicit registration is auditable, predictable, and compile-time verified.
ABSTRACT + CONCRETE PATTERN
EK9 components follow the abstract/concrete pattern: define an abstract component (the contract), then implement concrete components. Register the concrete as the abstract in the application. Programs inject the abstract type.
WHY NO @SERVICE/@REPOSITORY DISTINCTION
Spring has @Component, @Service, @Repository, and @Controller. These are functionally identical (all are component stereotypes). EK9 has one construct: component. Semantic distinctions belong in naming, not annotations.
See Q111 for component basics. See Q227 for compile-time validation. See Q324 for @Autowired equivalent. See Q326 for @Bean/@Configuration equivalent.
Example
defines module qa.di.spring.component defines component <?- Abstract component is the contract (like Spring interface). -?> NotificationService as abstract notify() as abstract -> message as String <- confirmation as String? default operator ? <?- Concrete component is the implementation (like @Service class). -?> EmailNotifier is NotificationService override notify() -> message as String <- confirmation as String: "Email sent: " + message default operator ? AuditService as abstract record() as abstract -> action as String <- entry as String? default operator ? SimpleAuditService is AuditService notifier as NotificationService! override record() -> action as String <- entry <- String() entry: notifier.notify("Audit: " + action) default operator ? defines application ComponentApp register EmailNotifier() as NotificationService register SimpleAuditService() as AuditService defines program ComponentServiceDemo() with application of ComponentApp stdout <- Stdout() // === COMPONENTS REPLACE @Component AND @Service === audit as AuditService! result <- audit.record("user.login") stdout.println(result) stdout.println("Components defined in 'defines component' section")
Common mistakes
E08150 — Injection fields must declare the abstract component type. The concrete EmailNotifier is registered against the abstract NotificationService in the application, not injected directly. See ek9 -h E08150 for details.
Incorrect:
notifier as EmailNotifier!
Correct:
notifier as NotificationService!
E08200 — SimpleAuditService injects NotificationService, so NotificationService must be registered before SimpleAuditService. Reversing the order causes a missing dependency at that point in the registration sequence. See ek9 -h E08200 for details.
Incorrect:
register SimpleAuditService() as AuditService register EmailNotifier() as NotificationService
Correct:
register EmailNotifier() as NotificationService register SimpleAuditService() as AuditService
E50001 — Renaming the variable means later references to 'result' become unresolved, triggering E50001. See ek9 -h E50001 for details.
Incorrect:
resultXYZ <- audit.record("user.login")
Correct:
result <- audit.record("user.login")
Other ways to ask this
- How do I define injectable components in EK9?
- What replaces @Component and @Service annotations in EK9?
- How does EK9 component scanning work?
Coming from another language?
Java Spring: @Component, @Service, @Repository, @Controller stereotypes with classpath scanning. Guice: @Provides methods in Module classes. .NET: services.AddTransient/AddScoped/AddSingleton in ConfigureServices. Python: no language-level component declaration. Go: no language-level DI. EK9: 'defines component' section with abstract/concrete pattern, explicit registration in application, no classpath scanning.
Keywords: injectable, define, register, annotation, construct, inject, spring, component, migration, stereotype, dependency, service