Skip to content

JSR-330 兼容性

Koin 通过 Koin 注解和 Kotlin 编译器插件提供完整的 JSR-330 (Jakarta Inject) 兼容性。这使得 Koin 成为从 Hilt、Dagger 或其他 JSR-330 兼容框架迁移的团队的绝佳选择。

为什么选择 JSR-330?

JSR-330 为 Java/Kotlin 中的依赖项注入定义了一套标准注解:

JSR-330 注解Koin 等效项用途
@Inject构造函数检测标记可注入的构造函数
@Singleton@Single单例实例作用域
@Named@Named基于字符串的限定符
@Qualifier@Qualifier自定义限定符注解
@Scope@Scope自定义作用域注解

设置

在您的项目中添加 koin-jsr330 依赖项:

kotlin
dependencies {
    implementation("io.insert-koin:koin-jsr330:$koin_version")
}

基本用法

@Singleton 和 @Inject

您现有的 Hilt/Dagger 类可以与 Koin 配合使用:

kotlin
import jakarta.inject.Inject
import jakarta.inject.Singleton

@Singleton
class UserRepository @Inject constructor(
    private val api: ApiService,
    private val database: UserDatabase
)

@Singleton
class ApiService @Inject constructor(
    private val httpClient: OkHttpClient
)

@Named 限定符

基于字符串的限定符工作方式完全相同:

kotlin
import jakarta.inject.Named
import jakarta.inject.Singleton

@Singleton
@Named("api")
class ApiOkHttpClient @Inject constructor() : OkHttpClient()

@Singleton
@Named("image")
class ImageOkHttpClient @Inject constructor() : OkHttpClient()

@Singleton
class NetworkManager @Inject constructor(
    @Named("api") private val apiClient: OkHttpClient,
    @Named("image") private val imageClient: OkHttpClient
)

自定义 @Qualifier 注解

保留您现有的自定义限定符:

kotlin
import jakarta.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IoDispatcher

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MainDispatcher

@Singleton
class CoroutineModule {
    @IoDispatcher
    fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO

    @MainDispatcher
    fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
}

@Singleton
class DataSyncManager @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher
)

Android ViewModel

JSR-330 注解支持 Koin 的 ViewModel:

kotlin
import jakarta.inject.Inject

@KoinViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    fun loadUser(id: String) {
        viewModelScope.launch {
            val user = userRepository.getUser(id)
            // ...
        }
    }
}

NOTE

对于 ViewModel,请使用 @KoinViewModel (Koin 注解)。JSR-330 未定义 ViewModel 注解。

从 Hilt 迁移

之前 (Hilt)

kotlin
@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject lateinit var analytics: Analytics
}

@Singleton
class Analytics @Inject constructor(
    @ApplicationContext private val context: Context
)

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com")
        .build()
}

之后 (Koin 搭配 JSR-330)

kotlin
// Application - 使用 startKoin
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@MyApplication)
            modules(appModule)
        }
    }
}

// Activity - 使用 by inject()
class MainActivity : AppCompatActivity() {
    private val analytics: Analytics by inject()
}

// 保持 @Singleton 和 @Inject 不变!
@Singleton
class Analytics @Inject constructor(
    private val context: Context  // Koin 自动提供 Context
)

// 使用 @Single 为提供的实例配置模块
@Module
@ComponentScan
class NetworkModule {
    @Single
    fun provideRetrofit(): Retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com")
        .build()
}

混合使用

您可以在同一个项目中自由混合使用 JSR-330 和 Koin 注解:

kotlin
// JSR-330 风格
@Singleton
@Named("local")
class LocalDatabase @Inject constructor() : Database

// Koin 风格
@Single
@Named("remote")
class RemoteDatabase(private val api: ApiService) : Database

// 混合风格 - 带有 JSR-330 注入的 Koin 注解
@Factory
class DatabaseManager @Inject constructor(
    @Named("local") private val local: Database,
    @Named("remote") private val remote: Database
)

编译器插件支持

Koin 编译器插件也能识别 JSR-330 注解:

kotlin
// 这些在编译器插件中是等效的
@Singleton
class UserRepository @Inject constructor(private val api: ApiService)

// 编译器插件 DSL (生成相同的代码)
val module = module {
    single<UserRepository>()
}

优势

  • 零代码更改 - 现有的 @Inject@Singleton 注解可以直接使用
  • 渐进式迁移 - 逐个模块进行迁移,混合使用 Hilt 和 Koin
  • 符合标准 - JSR-330 是 Java/Kotlin 标准,并非特定于框架
  • 团队熟悉度 - 开发者在 Hilt/Dagger 中已经熟悉了这些注解
  • 工具链支持 - IDE 对 JSR-330 注解的支持

局限性

一些 Hilt 特有的功能没有直接的 JSR-330 等效项:

Hilt 功能Koin 方案
@HiltAndroidApp在 Application 中使用 @KoinApplication + startKoin<T>{}
@AndroidEntryPointby inject() 扩展函数
@HiltViewModel@KoinViewModel
@ApplicationContextContext 参数 (自动注入)
@ActivityContext基于作用域的上下文解析

下一步