Android 實現一個依賴注入的注解
🎯 目標功能
- 自定義注解
@Inject
- 創建一個
Injector
類,用來掃描并注入對象 - 支持 Activity 或其他類中的字段注入
🧩 步驟一:定義注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}
🧩 步驟二:實現注入邏輯
import java.lang.reflect.Field;public class Injector {public static void inject(Object target) {Class<?> clazz = target.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Inject.class)) {try {Class<?> type = field.getType();Object instance = type.newInstance(); // 也可以用構造器緩存池優化field.setAccessible(true);field.set(target, instance);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("Failed to inject " + field.getName());}}}}
}
🧩 步驟三:使用示例
要實例化的對象類
import android.util.Log;public class Service {public void doSomething() {System.out.println("Service is working");Log.i("ServiceTAG", "Service is doSomething");}
}
在MainActivity注入
public class MainActivity extends AppCompatActivity {@InjectService service;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 注入邏輯Injector.inject(this); // 使用注入的對象service.doSomething(); }
}
? 補充建議
- 為了更靈活,你可以改用 構造器注入 或 單例管理。
- 如果要支持參數構造函數、依賴圖、作用域管理,可以逐步擴展。
- 如果你對性能敏感,可以考慮使用 APT(注解處理器) 生成代碼。
逐段解釋一下上述代碼:
🔧 一、自定義注解 @Inject
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}
? 解讀:
- @Target(ElementType.FIELD)
表示這個注解只能用于 字段上,不能用于類、方法等。 - @Retention(RetentionPolicy.RUNTIME)
表示這個注解在 運行時依然存在,這樣我們就可以通過反射獲取它。 - public @interface Inject {}
這是定義了一個名為 Inject 的注解,它 不包含任何參數,只作為標記使用。
🧠 二、注入器類 Injector
public class Injector {public static void inject(Object target) {Class<?> clazz = target.getClass();Field[] fields = clazz.getDeclaredFields();
? 解讀:
inject(Object target)
:這是一個靜態方法,接收需要注入依賴的對象,比如Activity
。target.getClass()
:獲取目標類的Class
對象。clazz.getDeclaredFields()
:獲取這個類里 聲明的所有字段(不管是私有還是公有)。
for (Field field : fields) {if (field.isAnnotationPresent(Inject.class)) {
? 解讀:
-
遍歷所有字段,檢查有沒有使用我們自定義的
@Inject
注解。try {Class<?> type = field.getType();Object instance = type.newInstance(); // 創建實例
? 解讀:
field.getType()
:獲取字段的類型,比如是Service.class
。type.newInstance()
:用 默認無參構造函數 實例化對象。
?? 這里假設被注入的類必須有一個無參構造函數。
field.setAccessible(true);field.set(target, instance);
? 解讀:
setAccessible(true)
:允許訪問私有字段。field.set(target, instance)
:將我們創建好的實例注入到目標對象的字段中。
} catch (Exception e) {e.printStackTrace();throw new RuntimeException("Failed to inject " + field.getName());}}}}
}
? 解讀:
- 如果注入失敗就打印異常并拋出運行時異常,方便調試。
💡 三、使用方式解析
public class MainActivity extends AppCompatActivity {@InjectService service;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Injector.inject(this); // 調用注入器注入service.doSomething(); // 使用注入后的 service}
}
? 解讀:
- 使用了
@Inject
標記字段,告訴注入器需要注入這個字段。 Injector.inject(this)
:告訴系統對這個對象(MainActivity)做依賴注入。service.doSomething()
:使用注入后的對象方法。
📌 總結核心原理
步驟 | 描述 |
---|---|
1 | 定義注解,告訴系統哪些字段要注入 |
2 | 通過反射找出所有有注解的字段 |
3 | 為這些字段創建對應實例 |
4 | 把實例賦值給這些字段 |