dagger2实现原理
Dagger
是一个依赖注入框架,最初由 Square 开发,后来由 Google 维护。Dagger
的设计目的是为了简化 Java 和 Kotlin 应用程序中的依赖管理和生命周期管理。Dagger
的两个主要版本是 Dagger 1
和 Dagger 2
,其中 Dagger 2
是目前推荐使用的版本,因为它使用静态类型安全的依赖注入,并且在编译时生成代码,而不是运行时,从而提高了性能和可调试性。
Dagger 2 的实现原理
1. 编译时代码生成
Dagger 2
通过编译时代码生成来实现依赖注入。它使用注解处理器(Annotation Processor)来分析应用中使用了 Dagger
注解的类和接口,然后生成相应的绑定代码。这意味着所有的依赖关系和绑定逻辑都在编译时被解析和验证,减少了运行时的开销。
2. Component 和 Module
Dagger
使用 Component
和 Module
的概念来组织和管理依赖注入。
-
Component:
Component
是Dagger
的依赖注入容器,它负责创建和管理依赖图。Component
通过@Component
注解定义,可以被看作是依赖注入的入口点。 -
Module:
Module
通过@Module
注解定义,它提供了一组绑定,用于描述如何创建或提供某些类型的实例。
3. 依赖注入注解
Dagger
提供了一系列的注解,用于描述依赖的提供、注入和作用域。
-
@Inject:用于标记需要被注入的构造函数、字段或方法。
-
@Provides:用于标记
Module
中提供依赖的方法。 -
@Singleton:用于标记在整个应用范围内只存在一个实例的依赖。
4. 作用域
Dagger
允许你定义依赖的作用域,例如 @Singleton
表示全局单例,或者自定义作用域注解来限定依赖的生命周期。
5. 依赖注入过程
当应用启动时,Dagger
会创建 Component
实例,并通过调用 inject()
方法来注入依赖到目标对象。Dagger
会根据 Component
和 Module
的定义,查找和创建所需的依赖实例。
源码层面的分析
Dagger
的核心组件之一是它的编译器插件,这个插件负责生成绑定代码。编译器插件会遍历所有使用了 Dagger
注解的类和接口,解析依赖关系,然后生成必要的代码,包括:
-
Component 实现:生成具体的
Component
实现,这些实现类包含了创建依赖实例的逻辑。 -
Provider 类:生成
Provider
类,用于在需要时提供依赖实例。 -
Binding 类:生成
Binding
类,用于描述如何创建或提供依赖实例。
当然,我可以给出一个具体的例子来分析 Dagger 2 的工作流程。让我们假设我们有一个简单的 Android 应用程序,其中包含以下几个类:
- AppComponent - Dagger 组件,应用程序级别的依赖注入点。
- AppModule - 提供应用程序范围的依赖。
- ActivityMain - 主 Activity,需要一些依赖。
- MyService - 一个服务类,需要被注入。
定义 AppComponent 和 AppModule
首先,我们定义 AppComponent 和 AppModule。
Java
1// AppComponent.java
2@Singleton
3@Component(modules = AppModule.class)
4public interface AppComponent {
5 void inject(ActivityMain activity);
6}
7
8// AppModule.java
9@Module
10public class AppModule {
11 @Provides
12 @Singleton
13 public MyService provideMyService() {
14 return new MyService();
15 }
16}
这里,@Component
注解定义了一个组件,并指定了模块。@Module
注解定义了一个模块,@Provides
注解则指定了如何提供 MyService 实例。
创建 ActivityMain 和 MyService
接下来,我们定义 ActivityMain 和 MyService。
Java
1// ActivityMain.java
2public class ActivityMain extends AppCompatActivity {
3 @Inject
4 MyService myService;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_main);
10
11 AppComponent component = DaggerAppComponent.create();
12 component.inject(this);
13
14 // 使用 myService
15 myService.doSomething();
16 }
17}
18
19// MyService.java
20public class MyService {
21 public void doSomething() {
22 // 执行一些操作
23 }
24}
在 ActivityMain 中,我们使用 @Inject
注解来标记 MyService 成员变量,表明它需要被注入。然后,在 onCreate
方法中,我们创建 AppComponent 并使用其 inject
方法来注入依赖。
分析 Dagger 的工作流程
当应用程序启动时,Dagger 2 的注解处理器会读取 @Component
和 @Module
注解,并生成以下内容:
- 生成一个
DaggerAppComponent
类,它实现了AppComponent
接口。 - 生成一个
AppModule_ProvidesMyServiceFactory
类,用于创建 MyService 实例。
在运行时,当 DaggerAppComponent.create()
被调用时,Dagger 会初始化并构建依赖图。然后,inject(ActivityMain activity)
方法会被调用,Dagger 会找到 MyService
的提供者(即 AppModule_ProvidesMyServiceFactory
),创建一个新的 MyService
实例(如果还没有被创建过)并将其注入到 ActivityMain 的 myService
字段中。
这就是 Dagger 2 如何在运行时处理依赖注入的过程。它利用注解处理器在编译时生成代码,从而避免了手动创建和管理依赖对象的复杂性。