使用Dagger Hilt添加AuthInterceptor时出现依赖循环问题
问题背景
添加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

