如何用Dagger 2实现Retrofit带授权与无授权接口服务的注入?
如何用Dagger 2迁移Retrofit认证服务配置
我来帮你一步步把原来RetrofitBuilder里的逻辑迁移到Dagger 2中,完美实现无认证和带认证的API调用,同时利用依赖注入的解耦优势。
1. 确保Dagger 2依赖配置(如果还没加)
首先确认你的app/build.gradle里已经添加了Dagger 2的核心依赖:
dependencies { // Dagger 2核心库 implementation 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' // 可选:AndroidX场景下的Dagger Android支持 implementation 'com.google.dagger:dagger-android:2.x' implementation 'com.google.dagger:dagger-android-support:2.x' annotationProcessor 'com.google.dagger:dagger-android-processor:2.x' }
2. 配置AppModule:提供核心依赖
在你的AppModule.java中,我们需要把所有核心依赖交给Dagger管理:
2.1 提供基础上下文与TokenManager
假设你的TokenManager负责Token的存储与读取,先把它纳入Dagger的管理范围:
@Module public class AppModule { private final Context context; public AppModule(Context context) { this.context = context; } @Provides @Singleton Context provideContext() { return context; } @Provides @Singleton TokenManager provideTokenManager(Context context) { return new TokenManager(context); } }
2.2 提供CustomAuthenticator实例
注意:刷新Token必须使用无认证的API服务,避免循环依赖,所以这里要提前注入无认证的ApiService(后面会配置):
@Provides @Singleton CustomAuthenticator provideCustomAuthenticator(TokenManager tokenManager, @Named("noAuth") ApiService noAuthApiService) { return new CustomAuthenticator(tokenManager, noAuthApiService); }
2.3 配置两种Retrofit实例(用@Named区分)
我们需要创建两个Retrofit实例:一个不带认证拦截器,一个自动携带Token并绑定刷新逻辑。用@Named注解让Dagger区分同类型的实例:
// 无认证Retrofit:用于登录、刷新Token等不需要Token的请求 @Provides @Singleton @Named("noAuth") Retrofit provideNoAuthRetrofit() { return new Retrofit.Builder() .baseUrl("YOUR_API_BASE_URL") .addConverterFactory(GsonConverterFactory.create()) .build(); } // 带认证Retrofit:自动添加Authorization头,绑定Token过期刷新逻辑 @Provides @Singleton @Named("auth") Retrofit provideAuthRetrofit(CustomAuthenticator authenticator, TokenManager tokenManager) { OkHttpClient okHttpClient = new OkHttpClient.Builder() // 自动添加Authorization头的拦截器 .addInterceptor(chain -> { Request originalRequest = chain.request(); Request authorizedRequest = originalRequest.newBuilder() .header("Authorization", "Bearer " + tokenManager.getAccessToken()) .build(); return chain.proceed(authorizedRequest); }) // 设置Token过期自动刷新的Authenticator .authenticator(authenticator) .build(); return new Retrofit.Builder() .baseUrl("YOUR_API_BASE_URL") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build(); }
2.4 提供两种ApiService实例
基于上面的两个Retrofit实例,创建对应的业务API服务(假设你的API接口是ApiService):
// 无认证的ApiService @Provides @Singleton @Named("noAuth") ApiService provideNoAuthApiService(@Named("noAuth") Retrofit retrofit) { return retrofit.create(ApiService.class); } // 带认证的ApiService @Provides @Singleton @Named("auth") ApiService provideAuthApiService(@Named("auth") Retrofit retrofit) { return retrofit.create(ApiService.class); }
3. 在UserRepository中注入两种服务
现在你可以在业务类(比如UserRepository)中通过构造函数注入这两个服务,按需调用:
public class UserRepository { private final ApiService noAuthApiService; private final ApiService authApiService; // 用@Inject标记构造函数,让Dagger自动注入依赖 @Inject public UserRepository(@Named("noAuth") ApiService noAuthApiService, @Named("auth") ApiService authApiService) { this.noAuthApiService = noAuthApiService; this.authApiService = authApiService; } // 示例:无认证请求(比如用户登录) public void performLogin(String email, String password, Callback<LoginResponse> callback) { noAuthApiService.login(email, password).enqueue(callback); } // 示例:带认证请求(比如获取用户个人信息) public void getUserProfile(Callback<UserProfile> callback) { authApiService.getUserProfile().enqueue(callback); } }
4. 配置Dagger Component并初始化
创建AppComponent接口,定义依赖注入的范围和可对外提供的实例:
@Singleton @Component(modules = {AppModule.class}) public interface AppComponent { // 注入Application(可选,如果你需要在Application中使用依赖) void inject(YourApplication application); // 对外提供UserRepository实例,供其他业务类获取 UserRepository userRepository(); }
然后在你的Application类中初始化Dagger Component:
public class YourApplication extends Application { private AppComponent appComponent; @Override public void onCreate() { super.onCreate(); // 初始化Dagger Component appComponent = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); // 注入Application本身(如果需要) appComponent.inject(this); } public AppComponent getAppComponent() { return appComponent; } }
5. 在业务代码中使用UserRepository
现在你可以在Activity、ViewModel等类中轻松获取UserRepository实例,调用对应接口:
// 在Activity中获取实例 UserRepository userRepository = ((YourApplication) getApplication()).getAppComponent().userRepository(); // 调用无认证登录接口 userRepository.performLogin("user@example.com", "password", new Callback<LoginResponse>() { @Override public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) { // 处理登录成功逻辑 } @Override public void onFailure(Call<LoginResponse> call, Throwable t) { // 处理登录失败逻辑 } }); // 调用带认证的用户信息接口 userRepository.getUserProfile(new Callback<UserProfile>() { @Override public void onResponse(Call<UserProfile> call, Response<UserProfile> response) { // 处理获取用户信息成功逻辑 } @Override public void onFailure(Call<UserProfile> call, Throwable t) { // 处理获取用户信息失败逻辑 } });
关键注意点
- @Named注解的必要性:因为两个Retrofit/ApiService类型完全相同,必须用
@Named或自定义限定符区分,否则Dagger会报错无法识别依赖。 - 避免循环依赖:CustomAuthenticator的刷新逻辑必须使用无认证的ApiService,不能依赖带认证的服务,否则会出现循环依赖问题。
- 单例Scope的使用:Retrofit、OkHttpClient、ApiService这些实例都应该设置为
@Singleton,避免重复创建对象,提升应用性能。
内容的提问来源于stack exchange,提问作者Sharoon Amjid
相关产品推荐
相关产品推荐

