Skip to content

组件化、路由与依赖注入深入详解

更新: 5/15/2026 字数: 0 字 时长: 0 分钟

1. 组件化架构设计

1.1 为什么要组件化

单体工程的问题:

  • 编译慢:改一行代码全量编译
  • 耦合重:模块间直接引用,牵一发动全身
  • 协作难:多团队改同一个模块容易冲突
  • 无法独立运行:不能单独调试某个业务模块

组件化的目标:

app(壳工程,只做组装)
├── feature-home(首页模块)
├── feature-video(视频模块)
├── feature-user(用户模块)
├── feature-search(搜索模块)
├── lib-network(网络库)
├── lib-image(图片库)
├── lib-common(公共工具)
└── lib-base(基础框架)

1.2 模块分层

┌─────────────────────────────────────┐
│              app(壳工程)            │  ← 只做模块组装和初始化
├─────────────────────────────────────┤
│  feature-home │ feature-video │ ... │  ← 业务模块(互相不依赖)
├─────────────────────────────────────┤
│  lib-network  │ lib-image │ lib-db  │  ← 功能模块(可被业务模块依赖)
├─────────────────────────────────────┤
│           lib-common                │  ← 公共工具(所有模块可依赖)
├─────────────────────────────────────┤
│           lib-base                  │  ← 基础框架(接口定义、路由表)
└─────────────────────────────────────┘

核心原则:

  • 业务模块之间不能直接依赖(通过路由或接口下沉通信)
  • 上层可以依赖下层,下层不能依赖上层
  • 公共接口下沉到 lib-base

1.3 模块独立运行

groovy
// feature-home/build.gradle.kts
// 通过 gradle.properties 中的标志位切换 application/library
if (isRunAlone) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    defaultConfig {
        if (isRunAlone) {
            applicationId "com.example.home"
        }
    }

    sourceSets {
        main {
            if (isRunAlone) {
                // 独立运行时使用独立的 AndroidManifest(有 launcher Activity)
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }
}

1.4 组件间通信方案

方案1:接口下沉 + SPI

kotlin
// lib-base 中定义接口
interface IUserService {
    fun getUserInfo(): UserInfo
    fun isLoggedIn(): Boolean
}

// feature-user 中实现
class UserServiceImpl : IUserService {
    override fun getUserInfo() = UserRepository.getUser()
    override fun isLoggedIn() = TokenManager.hasToken()
}

// 注册(通过 SPI 或手动注册)
// META-INF/services/com.example.base.IUserService
// com.example.user.UserServiceImpl

// 使用(在 feature-home 中)
val userService = ServiceLoader.load(IUserService::class.java).first()
if (userService.isLoggedIn()) { ... }

方案2:路由框架(ARouter)

kotlin
// feature-user 中暴露服务
@Route(path = "/user/service")
class UserServiceImpl : IProvider, IUserService {
    override fun getUserInfo() = UserRepository.getUser()
    override fun init(context: Context) {}
}

// feature-home 中使用
val userService = ARouter.getInstance()
    .build("/user/service")
    .navigation() as IUserService

方案3:EventBus / LiveDataBus

kotlin
// 发送事件(feature-user)
LiveDataBus.get<LoginEvent>("login_event").post(LoginEvent(userId))

// 接收事件(feature-home)
LiveDataBus.get<LoginEvent>("login_event").observe(this) { event ->
    refreshUserInfo(event.userId)
}

2. 路由框架原理(以 ARouter 为例)

2.1 整体架构

编译期(APT)                    运行时
┌──────────────┐            ┌──────────────┐
│ @Route 注解   │            │ ARouter.init │
│ RouteProcessor│ ──生成──→  │ 加载路由表     │
│ 生成路由表类   │            │              │
└──────────────┘            │ navigation() │
                            │ 匹配路由      │
                            │ 执行拦截器    │
                            │ 跳转/获取服务  │
                            └──────────────┘

2.2 编译期:APT 生成路由表

java
// 你写的代码
@Route(path = "/home/main")
public class HomeActivity extends AppCompatActivity { ... }

@Route(path = "/user/detail")
public class UserDetailActivity extends AppCompatActivity { ... }

// APT 生成的代码(每个模块一个类)
public class ARouter$$Group$$home implements IRouteGroup {
    @Override
    public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/home/main", RouteMeta.build(
            RouteType.ACTIVITY,
            HomeActivity.class,
            "/home/main",
            "home",  // group
            null,    // paramsType
            -1       // priority
        ));
    }
}

// 根路由表(索引 group → 对应的 IRouteGroup 类)
public class ARouter$$Root$$app implements IRouteRoot {
    @Override
    public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("home", ARouter$$Group$$home.class);
        routes.put("user", ARouter$$Group$$user.class);
    }
}

2.3 运行时:路由查找与跳转

java
// ARouter.init() 加载路由表
public static void init(Application application) {
    // 1. 扫描 dex 文件,找到所有 ARouter$$Root$$ 开头的类
    Set<String> routerMap = ClassUtils.getFileNameByPackageName(
        context, "com.alibaba.android.arouter.routes");

    // 2. 反射实例化,加载路由表到内存
    for (String className : routerMap) {
        if (className.startsWith(ROOT_PREFIX)) {
            ((IRouteRoot) Class.forName(className).newInstance())
                .loadInto(Warehouse.groupsIndex);
        }
    }
}

// navigation() 跳转
public Object navigation(Context context, Postcard postcard, int requestCode) {
    // 1. 根据 path 查找路由信息
    LogisticsCenter.completion(postcard);
    // 内部:从 Warehouse.routes 中查找 RouteMeta
    // 如果 group 还没加载,先加载 group

    // 2. 执行拦截器链
    interceptorService.doInterceptions(postcard, new InterceptorCallback() {
        @Override
        public void onContinue(Postcard postcard) {
            // 3. 拦截器通过,执行跳转
            _navigation(context, postcard, requestCode);
        }

        @Override
        public void onInterrupt(Throwable exception) {
            // 被拦截
        }
    });
}

private Object _navigation(Context context, Postcard postcard, int requestCode) {
    switch (postcard.getType()) {
        case ACTIVITY:
            Intent intent = new Intent(context, postcard.getDestination());
            intent.putExtras(postcard.getExtras());
            ActivityCompat.startActivityForResult(activity, intent, requestCode);
            break;

        case PROVIDER:
            // 获取服务实例(单例)
            return postcard.getProvider();

        case FRAGMENT:
            // 创建 Fragment 实例
            Fragment fragment = postcard.getDestination().newInstance();
            fragment.setArguments(postcard.getExtras());
            return fragment;
    }
}

2.4 拦截器

kotlin
// 登录拦截器:未登录时跳转到登录页
@Interceptor(priority = 8, name = "登录拦截器")
class LoginInterceptor : IInterceptor {
    override fun process(postcard: Postcard, callback: InterceptorCallback) {
        if (postcard.extra == NEED_LOGIN && !UserManager.isLoggedIn()) {
            // 拦截,跳转到登录页
            ARouter.getInstance().build("/user/login").navigation()
            callback.onInterrupt(null)
        } else {
            // 放行
            callback.onContinue(postcard)
        }
    }

    override fun init(context: Context) {}
}

// 使用:标记需要登录的页面
@Route(path = "/order/detail", extras = NEED_LOGIN)
class OrderDetailActivity : AppCompatActivity()

2.5 降级策略

kotlin
// 全局降级:路由找不到时的兜底
class GlobalDegradeService : DegradeService {
    override fun onLost(context: Context, postcard: Postcard) {
        // 跳转到 404 页面或 H5 兜底页
        ARouter.getInstance()
            .build("/common/webview")
            .withString("url", "https://example.com${postcard.path}")
            .navigation()
    }

    override fun init(context: Context) {}
}

3. 依赖注入(Hilt)

3.1 Hilt 核心概念

kotlin
// 1. @HiltAndroidApp:触发 Hilt 代码生成,创建应用级组件
@HiltAndroidApp
class MyApplication : Application()

// 2. @AndroidEntryPoint:标记需要注入的 Android 类
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    // 3. @Inject:标记需要注入的字段
    @Inject lateinit var userRepository: UserRepository

    // 4. ViewModel 注入
    private val viewModel: MainViewModel by viewModels()
}

// 5. @HiltViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
    private val userRepository: UserRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel()

3.2 Module 和 Provides

kotlin
// 提供接口的实现
@Module
@InstallIn(SingletonComponent::class)  // 作用域:Application 级别
object NetworkModule {

    @Provides
    @Singleton  // 单例
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(LoggingInterceptor())
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)  // Hilt 自动注入 OkHttpClient
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

// 绑定接口到实现
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
    @Binds
    @Singleton
    abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
}

3.3 Scope(作用域)

kotlin
// Hilt 预定义的组件和作用域
@SingletonComponent@Singleton        → Application 生命周期
@ActivityRetainedComponent@ActivityRetainedScoped → ViewModel 生命周期(配置变更不销毁)
@ViewModelComponent@ViewModelScoped  → ViewModel 生命周期
@ActivityComponent@ActivityScoped   → Activity 生命周期
@FragmentComponent@FragmentScoped   → Fragment 生命周期
@ViewComponent@ViewScoped       → View 生命周期
@ServiceComponent@ServiceScoped    → Service 生命周期
kotlin
// 示例:Activity 级别的作用域
@Module
@InstallIn(ActivityComponent::class)
object ActivityModule {
    @Provides
    @ActivityScoped  // 每个 Activity 实例一个,Activity 销毁时释放
    fun provideAnalytics(activity: Activity): AnalyticsTracker {
        return AnalyticsTracker(activity)
    }
}

3.4 Qualifier(限定符)

kotlin
// 同一类型有多个实现时,用 Qualifier 区分
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptor

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class LoggingInterceptor

@Module
@InstallIn(SingletonComponent::class)
object InterceptorModule {
    @Provides
    @AuthInterceptor
    fun provideAuthInterceptor(): Interceptor = AuthInterceptorImpl()

    @Provides
    @LoggingInterceptor
    fun provideLoggingInterceptor(): Interceptor = HttpLoggingInterceptor()
}

// 使用时指定
@Provides
fun provideOkHttpClient(
    @AuthInterceptor authInterceptor: Interceptor,
    @LoggingInterceptor loggingInterceptor: Interceptor
): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(authInterceptor)
        .addInterceptor(loggingInterceptor)
        .build()
}

3.5 Hilt 的编译期原理

Hilt 在编译期做了什么:

1. @HiltAndroidApp 处理
   → 生成 Hilt_MyApplication(继承 MyApplication)
   → 在 AndroidManifest 中替换 Application 类名
   → 创建 SingletonComponent(Dagger 组件)

2. @AndroidEntryPoint 处理
   → 生成 Hilt_MainActivity(继承 MainActivity)
   → 在 onCreate 中调用 inject()
   → 从对应的 Component 中获取依赖并注入

3. @Module + @InstallIn 处理
   → 将 Module 安装到指定的 Component
   → 生成 Dagger 的依赖图(DAG)
   → 编译期验证依赖是否完整(缺少依赖会编译报错)

与手动依赖管理的对比:

kotlin
// 手动创建(没有 DI)
val okHttpClient = OkHttpClient.Builder().build()
val retrofit = Retrofit.Builder().client(okHttpClient).build()
val apiService = retrofit.create(ApiService::class.java)
val repository = UserRepositoryImpl(apiService)
val viewModel = MainViewModel(repository)
// 问题:创建顺序、生命周期、单例管理全靠手动

// Hilt(自动管理)
@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: UserRepository  // Hilt 自动创建并注入整条依赖链
) : ViewModel()