最近在學(xué)習(xí) Java 的 Spring Boot 框架, 知道其精髓就是 DI 和 AOP, 其中對(duì)于 DI(依賴注入), 我是比較感興趣的莫矗,于是在網(wǎng)上查閱了一些資料面褐,大概了解到了其大概原理是通過反射和注解來實(shí)現(xiàn)的弧轧,我先前還一直以為可以通過 Java 的注解和 TS 的裝飾器是一樣的谅辣,看過文檔后才發(fā)現(xiàn)兩個(gè)是有些不同的凄吏。
簡單比較下:
- Java 的注解是有元注解來描述自定義的注解铸敏,注解里面可以添加屬性 然后還有屬性默認(rèn)值,需要配合反射才能發(fā)揮出對(duì)應(yīng)的作用
- TS 的裝飾器更像是函數(shù)杈帐,對(duì)目標(biāo)進(jìn)行修飾, 直接進(jìn)行修改
依賴注入的概念來講還是很簡單的体箕,就是在面向?qū)ο笾凶ǘぃ覀兊膶?duì)象不可能實(shí)現(xiàn)全部的功能,有時(shí)候需要?jiǎng)e的一些對(duì)象加入進(jìn)來作為一個(gè)依賴
public class Main {
// need logger to do something...
private Logger logger = new Logger();
}
上述的 demo 中, 我們的 Main 對(duì)象 需要一個(gè) logger 來打印一些日志, 那我們就需要給他一個(gè) logger 的實(shí)例累铅,這就是最簡單的依賴注入了
但是的話跃须,如果每次需要一個(gè)新的依賴進(jìn)來,我們都需要寫一遍的 new XXX, 秉承 DRY 的原則娃兽,我們可以通過注解+反射的方式來做些處理菇民,讓注入的依賴自動(dòng)返回實(shí)例, 而不需要手動(dòng)地去 new
首先我們先聲明一個(gè)注解來表示屬性是需要進(jìn)行依賴注入的
public class animation {
// 表示注解作用于屬性上
@Target(value = { ElementType.FIELD })
// 表示注解在運(yùn)行時(shí)依然可用
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Inject {
}
}
通過@Injenct 注解我們可以去注明那一些是需要進(jìn)行依賴注入的。
public class Main {
@inject
private Logger logger;
}
然后通過反射來獲取注解
public class Parse {
public static <T> T getBean(Class<T> c) {
T result = null;
try {
result = c.newInstance();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
Inject inject = field.getAnnotation(Inject.class);
if (inject != null) {
// 遞歸解決依賴問題
Object object = parse.getBean(field.getType());
// 針對(duì)private
if (!field.isAccessible())
field.setAccessible(true);
field.set(result, object);
}
}
} catch (Exception e) {
System.out.println(e);
}
return result;
}
}
簡單描述下上面的過程: 1.獲取運(yùn)行時(shí)的注解投储,但凡是有@Inject 的注解則進(jìn)行第 2 步 2.通過 field.getType()獲取注入的 class, 通過遞歸進(jìn)行對(duì)一層層的依賴進(jìn)行處理, 注意最后會(huì)返回注入的 class 的實(shí)例, 跳至第 3 步 3.如果 field 不可訪問第练,則進(jìn)行 setAccessible(true), 跳至第 4 步 4.對(duì)對(duì)應(yīng)的 field(屬性)進(jìn)行設(shè)置, 完成整個(gè)依賴注入的過程