JSR-330 호환성
Koin은 Koin Annotations와 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 | @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 한정자 (Qualifiers)
문자열 기반 한정자도 동일하게 작동합니다:
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
)안드로이드 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()
}이후 (JSR-330을 사용한 Koin)
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를 통해 이러한 어노테이션에 익숙합니다.
- 도구 지원 - JSR-330 어노테이션에 대한 IDE 지원이 제공됩니다.
제한 사항
일부 Hilt 전용 기능은 직접적인 JSR-330 대응 요소가 없습니다:
| Hilt 기능 | Koin 방식 |
|---|---|
@HiltAndroidApp | Application에서 @KoinApplication + startKoin<T>{} 사용 |
@AndroidEntryPoint | by inject() 확장 함수 사용 |
@HiltViewModel | @KoinViewModel |
@ApplicationContext | Context 파라미터 (자동 주입됨) |
@ActivityContext | 스코프 기반 컨텍스트 해결(Resolution) |
다음 단계
- Hilt 마이그레이션 가이드 - 전체 마이그레이션 절차 안내
- 한정자(Qualifiers) - Koin의 모든 한정자 옵션
- 정의(Definitions) - JSR-330 어노테이션 전체 레퍼런스
