Hilt依赖循环问题求助:拦截器中如何调用ApiService
我在使用Hilt时遇到了[Dagger/DependencyCycle]依赖循环错误,想通过拦截器在令牌过期时完成刷新操作,但修复未果。以下是相关代码和错误信息:
AuthInterceptor类代码
class AuthInterceptor @Inject constructor(private val apiService: ApiService) : Interceptor, Authenticator { private val preferenceProvider = PreferenceProvider() override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() request = request.newBuilder() .addHeader("Content-Type", "application/json") .addHeader("Accept", "application/json") .build() return chain.proceed(request) } override fun authenticate(route: Route?, response: Response): Request? { val token = preferenceProvider.getString(PREF_TOKEN) ?: return null // 此处计划调用apiService的刷新令牌方法 return null } }
NetworkModule类代码
@Module @InstallIn(SingletonComponent::class) object NetworkModule { @Singleton @Provides fun provideHttpClient(authInterceptor: AuthInterceptor): OkHttpClient { val interceptor = HttpLoggingInterceptor() interceptor.level = HttpLoggingInterceptor.Level.HEADERS interceptor.level = HttpLoggingInterceptor.Level.BODY val builder = OkHttpClient.Builder() builder.addInterceptor(interceptor) .connectTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .addInterceptor(authInterceptor) .authenticator(authInterceptor) return builder.build() } @Singleton @Provides fun provideConverterFactory(): GsonConverterFactory { return GsonConverterFactory.create() } @Singleton @Provides fun provideRetrofitInstance(okHttpClient: OkHttpClient, gsonConverterFactory: GsonConverterFactory) : Retrofit { return Retrofit.Builder().baseUrl("BASE_URL").client(okHttpClient).addConverterFactory(gsonConverterFactory).build() } @Singleton @Provides fun provideApiService(retrofit: Retrofit): ApiService { return retrofit.create(ApiService::class.java) } }
错误信息
.ApiService 被注入到
AuthInterceptor(apiService)
.AuthInterceptor 被注入到
.NetworkModule.provideHttpClient(authInterceptor)
okhttp3.OkHttpClient 被注入到
.NetworkModule.provideRetrofitInstance(okHttpClient, …)
retrofit2.Retrofit 被注入到
.NetworkModule.provideApiService(retrofit)
.ApiService 被注入到
.AuthInterceptor(apiService)
...
解决方案
1. 用Lazy<ApiService>打破依赖循环
依赖循环的核心是AuthInterceptor → ApiService → Retrofit → OkHttpClient → AuthInterceptor,使用Hilt的Lazy延迟初始化ApiService,避免创建AuthInterceptor时立刻触发ApiService的实例化。
修改AuthInterceptor的构造和使用逻辑:
class AuthInterceptor @Inject constructor( private val apiService: Lazy<ApiService>, private val preferenceProvider: PreferenceProvider // 建议改为注入,而非手动new ) : Interceptor, Authenticator { override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() request = request.newBuilder() .addHeader("Content-Type", "application/json") .addHeader("Accept", "application/json") .build() return chain.proceed(request) } override fun authenticate(route: Route?, response: Response): Request? { val token = preferenceProvider.getString(PREF_TOKEN) ?: return null // 通过apiService.value获取实例,此时OkHttpClient已创建完成 val refreshResponse = apiService.value.refreshToken(token).execute() val newToken = refreshResponse.body()?.token ?: return null preferenceProvider.putString(PREF_TOKEN, newToken) // 返回携带新令牌的请求 return response.request.newBuilder() .header("Authorization", "Bearer $newToken") .build() } }
2. 优化:避免刷新请求被拦截
为防止刷新令牌的请求被AuthInterceptor重复拦截导致无限循环,在intercept方法中添加路径判断:
override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() // 跳过刷新令牌接口的拦截逻辑 if (request.url.pathSegments.contains("refresh-token")) { return chain.proceed(request) } val modifiedRequest = request.newBuilder() .addHeader("Content-Type", "application/json") .addHeader("Accept", "application/json") .addHeader("Authorization", "Bearer ${preferenceProvider.getString(PREF_TOKEN)}") .build() return chain.proceed(modifiedRequest) }
3. 补充:注入PreferenceProvider
将手动创建的PreferenceProvider改为依赖注入,保持一致性:
// 给PreferenceProvider添加@Inject构造 class PreferenceProvider @Inject constructor( @ApplicationContext private val context: Context ) { // 原有逻辑 }
内容的提问来源于stack exchange,提问作者hanifedev

