0
# Component Integration
1
2
This document covers how to integrate dependency injection into your classes using Koin's component interfaces and extension functions.
3
4
## Overview
5
6
Koin provides component interfaces that enable seamless dependency injection integration:
7
- **KoinComponent** - Basic dependency injection capabilities
8
- **KoinScopeComponent** - Scope-aware dependency injection with lifecycle management
9
10
These interfaces provide extension functions that allow your classes to directly access the dependency injection container without explicitly passing around Koin instances.
11
12
## KoinComponent Interface
13
14
The basic interface for dependency injection integration:
15
16
```kotlin { .api }
17
interface KoinComponent {
18
fun getKoin(): Koin
19
}
20
```
21
22
### Extension Functions
23
24
```kotlin { .api }
25
// Direct resolution
26
inline fun <reified T : Any> KoinComponent.get(
27
qualifier: Qualifier? = null,
28
noinline parameters: ParametersDefinition? = null
29
): T
30
31
// Lazy injection
32
inline fun <reified T : Any> KoinComponent.inject(
33
qualifier: Qualifier? = null,
34
mode: LazyThreadSafetyMode = KoinPlatformTools.defaultLazyMode(),
35
noinline parameters: ParametersDefinition? = null
36
): Lazy<T>
37
```
38
39
### Basic Implementation
40
41
```kotlin
42
import org.koin.core.component.KoinComponent
43
import org.koin.core.component.get
44
import org.koin.core.component.inject
45
46
class UserService : KoinComponent {
47
// Direct injection - resolved immediately
48
private val repository: UserRepository = get()
49
50
// Lazy injection - resolved when first accessed
51
private val logger: Logger by inject()
52
53
// Qualified injection
54
private val cache: Cache = get(named("user"))
55
56
fun processUser(userId: String) {
57
logger.info("Processing user: $userId")
58
val user = repository.findById(userId)
59
// ... process user
60
}
61
}
62
```
63
64
### With Parameters
65
66
```kotlin
67
import org.koin.core.parameter.parametersOf
68
69
class ConfigurableService : KoinComponent {
70
fun createClient(endpoint: String, timeout: Int): ApiClient {
71
return get { parametersOf(endpoint, timeout) }
72
}
73
74
fun getEnvironmentConfig(): Config {
75
val env = System.getenv("ENVIRONMENT") ?: "development"
76
return get(named(env))
77
}
78
}
79
```
80
81
### Custom Koin Context
82
83
```kotlin
84
class IsolatedService(private val customKoin: Koin) : KoinComponent {
85
// Override to use custom Koin instance
86
override fun getKoin(): Koin = customKoin
87
88
private val service: DataService by inject()
89
}
90
```
91
92
## KoinScopeComponent Interface
93
94
The scope-aware interface that automatically manages scoped dependencies:
95
96
```kotlin { .api }
97
interface KoinScopeComponent : KoinComponent {
98
val scope: Scope
99
}
100
```
101
102
### Extension Functions
103
104
```kotlin { .api }
105
// Scope identification
106
fun <T : Any> T.getScopeId(): String
107
fun <T : Any> T.getScopeName(): TypeQualifier
108
109
// Scope creation
110
fun <T : KoinScopeComponent> T.createScope(
111
scopeId: ScopeID = getScopeId(),
112
source: Any? = null,
113
scopeArchetype: TypeQualifier? = null
114
): Scope
115
116
fun <T : KoinScopeComponent> T.createScope(source: Any? = null): Scope
117
118
// Scope access
119
fun <T : KoinScopeComponent> T.getScopeOrNull(): Scope?
120
121
// Lazy scope creation
122
fun <T : KoinScopeComponent> T.newScope(): Lazy<Scope>
123
fun <T : KoinScopeComponent> T.getOrCreateScope(): Lazy<Scope>
124
```
125
126
### Basic Scope Component
127
128
```kotlin
129
import org.koin.core.component.KoinScopeComponent
130
import org.koin.core.component.createScope
131
import org.koin.core.component.get
132
import org.koin.core.scope.Scope
133
134
class UserSession : KoinScopeComponent {
135
// Automatically creates scope for this instance
136
override val scope: Scope by lazy { createScope() }
137
138
// Scoped dependencies - shared within this session
139
private val sessionData: SessionData by inject()
140
private val preferences: UserPreferences by inject()
141
142
fun login(credentials: Credentials) {
143
// Dependencies are resolved from this instance's scope
144
sessionData.initialize(credentials.userId)
145
preferences.load(credentials.userId)
146
}
147
148
fun logout() {
149
// Close scope when session ends
150
scope.close()
151
}
152
}
153
```
154
155
### Manual Scope Management
156
157
```kotlin
158
class CustomScopeComponent : KoinScopeComponent {
159
private var _scope: Scope? = null
160
161
override val scope: Scope
162
get() = _scope ?: throw IllegalStateException("Scope not initialized")
163
164
fun initialize() {
165
_scope = createScope()
166
}
167
168
fun cleanup() {
169
_scope?.close()
170
_scope = null
171
}
172
}
173
```
174
175
### Scope Resolution Behavior
176
177
When using `KoinScopeComponent`, the `get()` and `inject()` functions automatically use the component's scope:
178
179
```kotlin
180
class ScopedService : KoinScopeComponent {
181
override val scope: Scope by lazy { createScope() }
182
183
fun example() {
184
// These resolve from the component's scope
185
val service1: MyService = get() // scope.get<MyService>()
186
val service2: MyService by inject() // scope.inject<MyService>()
187
188
// Equivalent explicit calls
189
val service3: MyService = scope.get()
190
val service4: MyService by scope.inject()
191
}
192
}
193
```
194
195
## Practical Implementation Patterns
196
197
### Service Layer Integration
198
199
```kotlin
200
// Business service with dependency injection
201
class OrderService : KoinComponent {
202
private val orderRepository: OrderRepository by inject()
203
private val paymentService: PaymentService by inject()
204
private val emailService: EmailService by inject()
205
private val logger: Logger by inject()
206
207
fun processOrder(order: Order): OrderResult {
208
logger.info("Processing order ${order.id}")
209
210
return try {
211
// Validate order
212
val validatedOrder = validateOrder(order)
213
214
// Process payment
215
val payment = paymentService.processPayment(validatedOrder.total)
216
217
// Save order
218
val savedOrder = orderRepository.save(validatedOrder.copy(paymentId = payment.id))
219
220
// Send confirmation
221
emailService.sendOrderConfirmation(savedOrder)
222
223
OrderResult.Success(savedOrder)
224
} catch (e: Exception) {
225
logger.error("Failed to process order ${order.id}", e)
226
OrderResult.Failure(e.message)
227
}
228
}
229
230
private fun validateOrder(order: Order): Order {
231
// Validation logic
232
return order
233
}
234
}
235
```
236
237
### UI Component Integration
238
239
```kotlin
240
// Android ViewModel example
241
class UserViewModel : KoinComponent {
242
private val userService: UserService by inject()
243
private val analyticsService: AnalyticsService by inject(named("firebase"))
244
245
private val _users = MutableLiveData<List<User>>()
246
val users: LiveData<List<User>> = _users
247
248
fun loadUsers() {
249
viewModelScope.launch {
250
try {
251
val userList = userService.getAllUsers()
252
_users.value = userList
253
analyticsService.track("users_loaded", mapOf("count" to userList.size))
254
} catch (e: Exception) {
255
// Handle error
256
}
257
}
258
}
259
}
260
```
261
262
### Scoped Component Lifecycle
263
264
```kotlin
265
class RequestHandler : KoinScopeComponent {
266
// Each request gets its own scope
267
override val scope: Scope by lazy { createScope() }
268
269
private val requestData: RequestData by inject()
270
private val auditLogger: AuditLogger by inject()
271
272
fun handleRequest(request: HttpRequest): HttpResponse {
273
try {
274
// Process with scoped dependencies
275
auditLogger.logRequest(request)
276
277
val result = processRequest(request)
278
279
auditLogger.logResponse(result)
280
return result
281
282
} finally {
283
// Always cleanup scope
284
scope.close()
285
}
286
}
287
288
private fun processRequest(request: HttpRequest): HttpResponse {
289
// Business logic using scoped dependencies
290
return HttpResponse.ok()
291
}
292
}
293
```
294
295
### Factory with Component Integration
296
297
```kotlin
298
class ServiceFactory : KoinComponent {
299
fun createUserService(userId: String): UserService {
300
// Inject dependencies for the service
301
val repository: UserRepository = get()
302
val cache: Cache = get(named("user"))
303
304
return UserService(userId, repository, cache)
305
}
306
307
fun createAdminService(adminLevel: Int): AdminService {
308
return get { parametersOf(adminLevel) }
309
}
310
}
311
```
312
313
## Advanced Component Patterns
314
315
### Component with Multiple Scopes
316
317
```kotlin
318
class MultiScopeComponent : KoinComponent {
319
private val globalKoin = getKoin()
320
321
// Different scopes for different contexts
322
private val sessionScope: Scope by lazy {
323
globalKoin.createScope<UserSession>("session-${sessionId()}")
324
}
325
326
private val requestScope: Scope by lazy {
327
globalKoin.createScope<RequestContext>("request-${requestId()}")
328
}
329
330
fun getSessionService(): SessionService = sessionScope.get()
331
fun getRequestService(): RequestService = requestScope.get()
332
333
private fun sessionId(): String = "session-123"
334
private fun requestId(): String = "request-456"
335
}
336
```
337
338
### Component with Conditional Injection
339
340
```kotlin
341
class ConditionalComponent : KoinComponent {
342
private val featureFlag: FeatureFlag by inject()
343
344
// Conditional lazy injection based on feature flags
345
private val newFeatureService: NewFeatureService? by lazy {
346
if (featureFlag.isEnabled("new_feature")) {
347
get<NewFeatureService>()
348
} else {
349
null
350
}
351
}
352
353
fun performAction() {
354
if (newFeatureService != null) {
355
newFeatureService.performNewAction()
356
} else {
357
// Fallback behavior
358
performLegacyAction()
359
}
360
}
361
362
private fun performLegacyAction() {
363
// Legacy implementation
364
}
365
}
366
```
367
368
### Component Inheritance
369
370
```kotlin
371
abstract class BaseComponent : KoinComponent {
372
protected val logger: Logger by inject()
373
protected val config: Config by inject()
374
375
protected fun logOperation(operation: String) {
376
logger.info("$operation in ${this::class.simpleName}")
377
}
378
}
379
380
class UserComponent : BaseComponent() {
381
private val userService: UserService by inject()
382
383
fun processUser(userId: String) {
384
logOperation("processUser") // Uses inherited logger
385
userService.process(userId)
386
}
387
}
388
389
class OrderComponent : BaseComponent() {
390
private val orderService: OrderService by inject()
391
392
fun processOrder(orderId: String) {
393
logOperation("processOrder") // Uses inherited logger
394
orderService.process(orderId)
395
}
396
}
397
```
398
399
## Testing with Components
400
401
### Component Testing
402
403
```kotlin
404
class TestableComponent : KoinComponent {
405
private val service: MyService by inject()
406
407
fun doSomething(): String {
408
return service.getData()
409
}
410
}
411
412
// Test with mock
413
@Test
414
fun testComponent() {
415
val testModule = module {
416
single<MyService> { mockk<MyService> {
417
every { getData() } returns "test data"
418
}}
419
}
420
421
val testApp = koinApplication { modules(testModule) }
422
423
val component = TestableComponent()
424
// Component uses test Koin context automatically
425
assertEquals("test data", component.doSomething())
426
}
427
```
428
429
### Scoped Component Testing
430
431
```kotlin
432
@Test
433
fun testScopedComponent() {
434
val testModule = module {
435
scope<TestScope> {
436
scoped<ScopedService> { mockk<ScopedService>() }
437
}
438
}
439
440
val koin = koinApplication { modules(testModule) }.koin
441
442
class TestComponent : KoinScopeComponent {
443
override val scope = koin.createScope<TestScope>("test")
444
445
fun getService(): ScopedService = get()
446
}
447
448
val component = TestComponent()
449
assertNotNull(component.getService())
450
451
component.scope.close()
452
}
453
```
454
455
## Best Practices
456
457
### 1. Use Lazy Injection for Expensive Resources
458
459
```kotlin
460
class OptimizedComponent : KoinComponent {
461
// Lazy injection - only created when needed
462
private val expensiveService: ExpensiveService by inject()
463
464
// Direct injection for lightweight dependencies
465
private val config: Config = get()
466
467
fun performOperation() {
468
// ExpensiveService is created here, not at component creation
469
expensiveService.doWork()
470
}
471
}
472
```
473
474
### 2. Proper Scope Lifecycle Management
475
476
```kotlin
477
class ProperScopeComponent : KoinScopeComponent {
478
override val scope: Scope by lazy { createScope() }
479
480
fun initialize() {
481
// Setup scope dependencies
482
}
483
484
fun cleanup() {
485
// Always close scope when done
486
if (!scope.closed) {
487
scope.close()
488
}
489
}
490
}
491
```
492
493
### 3. Avoid Direct Koin Access
494
495
```kotlin
496
// Good - uses component interface
497
class GoodComponent : KoinComponent {
498
private val service: MyService by inject()
499
}
500
501
// Avoid - direct Koin dependency
502
class AvoidComponent(private val koin: Koin) {
503
private val service: MyService = koin.get()
504
}
505
```
506
507
### 4. Component Interface Segregation
508
509
```kotlin
510
// Specific interfaces for different component types
511
interface ServiceComponent : KoinComponent
512
interface RepositoryComponent : KoinComponent
513
interface ScopedServiceComponent : KoinScopeComponent
514
515
class UserService : ServiceComponent {
516
private val repository: UserRepository by inject()
517
}
518
519
class UserSessionManager : ScopedServiceComponent {
520
override val scope: Scope by lazy { createScope() }
521
private val sessionData: SessionData by inject()
522
}
523
```
524
525
Component interfaces provide a clean, testable way to integrate dependency injection into your application architecture while maintaining loose coupling and supporting various lifecycle patterns.