You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Dagger Hilt添加AuthInterceptor时出现依赖循环问题

解决Dagger依赖循环问题:添加AuthInterceptor后出现[Dagger/DependencyCycle]错误

问题背景

添加AuthInterceptor之前所有依赖正常工作,添加后触发Dagger依赖循环检测错误,相关依赖注入代码如下:

提供OkHttpClient的代码

@Singleton
@Provides
fun provideOkHttpClient(
    authInterceptor: AuthInterceptor,
    apiConfiguration: ApiConfiguration,
    httpLoggingInterceptor: HttpLoggingInterceptor?,
): OkHttpClient {
    val okHttpClientBuilder = OkHttpClient.Builder()

    httpLoggingInterceptor?.level = HttpLoggingInterceptor.Level.BODY
    if (httpLoggingInterceptor != null) {
        okHttpClientBuilder.addInterceptor(httpLoggingInterceptor)
    }

    okHttpClientBuilder
        .addInterceptor(authInterceptor)
        .connectTimeout(apiConfiguration.timeout, TimeUnit.SECONDS)
        .readTimeout(apiConfiguration.timeout, TimeUnit.SECONDS)

    return okHttpClientBuilder.build()
}

提供AuthInterceptor的代码

@Singleton
@Provides
fun provideAuthInterceptor(
    sessionManager: SessionManager,
    refresher: Lazy<TokenRefresher>,
): AuthInterceptor {
    return AuthInterceptor(
        sessionManager = sessionManager,
        refresher = refresher,
    )
}

提供TokenRefresher的代码

@Singleton
@Provides
fun provideTokenRefresher(
    refreshTokenRepository: RefreshTokenRepository
): Lazy<TokenRefresher> {
    return lazy { TokenRefresher(refreshTokenRepository = refreshTokenRepository) }
}

绑定RefreshTokenRepository的代码

@Binds
abstract fun bindTokenRefresher(refreshTokenRepositoryImpl: DefaultRefreshTokenRepository): RefreshTokenRepository

问题原因

依赖循环的核心原因是:DefaultRefreshTokenRepository大概率依赖了由provideOkHttpClient创建的Retrofit API服务,而这个OkHttpClient又依赖AuthInterceptor,AuthInterceptor依赖Lazy<TokenRefresher>,TokenRefresher依赖RefreshTokenRepository,最终形成闭环:
OkHttpClient → AuthInterceptor → TokenRefresher → RefreshTokenRepository → API服务 → OkHttpClient

即使使用了Lazy延迟加载TokenRefresher,只要TokenRefresher最终依赖的Repo还是用到了带AuthInterceptor的OkHttpClient,循环依然存在。

解决方案

为Token刷新流程创建独立的OkHttpClient实例,这个实例不添加AuthInterceptor,避免参与循环:

1. 添加独立的刷新用OkHttpClient提供方法

@Singleton
@Provides
@Named("refresh")
fun provideRefreshOkHttpClient(
    apiConfiguration: ApiConfiguration,
    httpLoggingInterceptor: HttpLoggingInterceptor?,
): OkHttpClient {
    val okHttpClientBuilder = OkHttpClient.Builder()

    httpLoggingInterceptor?.level = HttpLoggingInterceptor.Level.BODY
    httpLoggingInterceptor?.let { okHttpClientBuilder.addInterceptor(it) }

    okHttpClientBuilder
        .connectTimeout(apiConfiguration.timeout, TimeUnit.SECONDS)
        .readTimeout(apiConfiguration.timeout, TimeUnit.SECONDS)

    // 注意:这里不要添加AuthInterceptor
    return okHttpClientBuilder.build()
}

2. 给原有OkHttpClient添加命名注解区分

修改原provideOkHttpClient方法,添加@Named注解标记为默认实例:

@Singleton
@Provides
@Named("default")
fun provideOkHttpClient(
    authInterceptor: AuthInterceptor,
    apiConfiguration: ApiConfiguration,
    httpLoggingInterceptor: HttpLoggingInterceptor?,
): OkHttpClient {
    // 原有代码保持不变
}

3. 为刷新token的API服务指定独立的OkHttpClient

在提供刷新token的Retrofit API服务时,注入命名为refresh的OkHttpClient:

@Singleton
@Provides
fun provideRefreshTokenApi(
    @Named("refresh") okHttpClient: OkHttpClient,
    retrofitBuilder: Retrofit.Builder
): RefreshTokenApi {
    return retrofitBuilder
        .client(okHttpClient)
        .build()
        .create(RefreshTokenApi::class.java)
}

4. 调整RefreshTokenRepository的依赖

让DefaultRefreshTokenRepository注入上述的RefreshTokenApi(使用独立OkHttpClient的实例),而不是依赖普通的API服务,彻底切断循环链。

调整后两条依赖链相互独立,不再形成闭环:

  • 普通API服务 → 带AuthInterceptor的OkHttpClient → AuthInterceptor → Lazy
  • TokenRefresher → RefreshTokenRepository → 刷新用API服务 → 无AuthInterceptor的OkHttpClient

内容的提问来源于stack exchange,提问作者Burak Karaduman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:25:25