KMP 插件框架:基于 SweetSPI + Koin 的模块化实践

8 阅读2分钟
# KMP 插件框架:基于 SweetSPI + Koin 的模块化实践

## 背景

插件化开发的核心目标是**在不修改核心代码的情况下动态添加功能**。通过 SPI(Service Provider Interface)机制实现插件自动发现,结合 Koin 完成依赖注入,可以在运行时自由组合功能模块,各模块独立开发、独立测试。

## 整体架构

```
┌─────────────────────────────────────────────┐
│                  App                         │
│                                              │
│  ┌─────────────────────────────────────┐    │
│  │         KoinApplication              │    │
│  │                                      │    │
│  │   modules(pluginModule)              │    │
│  │        │                             │    │
│  │        ▼                             │    │
│  │   pluginModule                       │    │
│  │   includes(userModule)               │    │
│  │   includes(orderModule)              │    │
│  │   includes(paymentModule)            │    │
│  │        │                             │    │
│  │        ▼                             │    │
│  │   ServiceLoader.load(BootModule)     │    │
│  │   ─ META-INF/services ─              │    │
│  └─────────────────────────────────────┘    │
└─────────────────────────────────────────────┘
```

核心思路:**Plugin 定义插件接口,ServiceLoader 实现自动发现,Koin 统一管理依赖**。

## 定义插件接口

定义一个 `Plugin` 接口,所有插件必须实现该接口。`module` 属性返回一个 Koin `Module`,用于注册插件自身的依赖:

```kotlin
interface Plugin {
    val module: Module
}
```

## 实现插件

以用户模块为例,定义业务依赖并实现 `Plugin````kotlin
internal val userModule = module {
    single { UserRepository() }
    single { UserService(get()) }
}

object UserPlugin : Plugin {
    override val module: Module = userModule
}
```

多个插件完全独立开发,互不感知。

## 自动发现插件

`PluginManager` 通过 Java SPI(`ServiceLoader`)在运行时加载所有 `Plugin` 实现类。KSP 处理器在编译时自动生成 `META-INF/services` 配置文件,无需手动维护:

```kotlin
object PluginManager {
    val plugins: List<Plugin> by lazy {
        ServiceLoader.load(Plugin::class.java).toList()
    }
}
```

生成的 `META-INF/services/com.yuanjingtech.boot.app.kmp.BootModule` 文件内容类似:

```
com.yuanjingtech.boot.app.kmp.user.UserBootModule
com.yuanjingtech.boot.app.kmp.order.OrderBootModule
com.yuanjingtech.boot.app.kmp.payment.PaymentBootModule
```

## 注册插件到 Koin

将所有插件的 `Module` 合并为一个 `pluginModule`,统一注入到 Koin:

```kotlin
val pluginModule = module {
    includes(PluginManager.plugins.map { it.module })
}
```

## 应用启动

在 Compose Multiplatform 应用中,通过 `KoinApplication` 启动:

```kotlin
@Composable
fun App() {
    KoinApplication(
        configuration = KoinConfiguration {
            modules(pluginModule)
        },
        content = {
            Content()
        }
    )
}
```

## 总结

整个插件框架的核心链路:

1. **定义接口**:`Plugin` 约束插件必须提供 `Module`
2. **实现插件**:各模块实现 `Plugin`,独立开发独立测试
3. **自动发现**:SweetSPI + KSP 自动生成 `META-INF/services``ServiceLoader` 运行时加载
4. **统一注入**:所有插件模块合并后统一注册到 Koin

这种模式实现了核心代码零修改即可扩展功能,适合模块化的大型 KMP 项目。