질문 정리

[Dagger/DependencyCycle] Found a dependency cycle

five2week 2024. 7. 12. 18:50

문제 상황

Dagger에서 "Found a dependency cycle" 오류는 Dagger의 종속성 주입 과정에서 의존성 사이클이 감지될 때 발생합니다. 이는 하나 이상의 클래스가 서로를 직접적이거나 간접적으로 의존하고 있어서 순환 의존성이 생긴 경우입니다. 이러한 순환 의존성은 Dagger가 의존성 그래프를 구성할 때 종료 조건을 만족시키지 못해 발생하는 문제입니다.

 

문제 분석

TokenAuthenticator: Authenticator가 ApiService: interface를 필요로 하고, 동시에 ApiService interface가 TokenAuthenticator:Authenticator를 포함하는 OkHttpClient: OkHttpClient를 필요로 하는 설정에서 순환 의존성이 발생할 수 있습니다. 즉, TokenAuthenticator -> ApiService -> OkHttpClient -> TokenAuthenticator로 이어지는 순환 구조가 문제입니다.

 

해결 방안

Provider를 사용하면 Dagger가 종속성을 즉시 주입하는 대신 필요할 때 주입할 수 있게 됩니다. 이를 통해 순환 의존성 문제를 해결할 수 있습니다.

 

Provider를 적용한 AppModule 코드

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Singleton
    @Provides
    fun provideUserData(): UserData {
        return UserData
    }
    
    @Provides
    fun provideTokenAuthenticator(
        apiServiceProvider: Provider<ApiService>,
        userData: UserData
    ): TokenAuthenticator {
        return TokenAuthenticator(apiServiceProvider, userData)
    }

    @Provides
    @Singleton
    fun provideOkHttpClient(
        tokenAuthenticator: TokenAuthenticator
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .authenticator(tokenAuthenticator)
            .build()
    }
}

Provider를 적용한 TokenAuthenticator 코드

class TokenAuthenticator @Inject constructor(
    // Provider 사용
    private val apiServiceProvider: Provider<ApiService>, 
    private val userData: UserData
) : Authenticator {
    override fun authenticate(route: Route?, response: Response): Request? {
        // 필요할 때 ApiService 인스턴스를 가져옴
        val apiService = apiServiceProvider.get() 
        // 토큰 갱신 로직
    }
}

 

이 변경을 통해 ApiService 인스턴스가 필요할 때만 Provider를 통해 가져오도록 함으로써 순환 의존성을 방지할 수 있습니다. 이렇게 함으로써 Dagger는 의존성 그래프를 성공적으로 구성할 수 있으며, 앱이 올바르게 컴파일되고 실행됩니다.