走馬觀花-Dagger2 - @Inject 和 @Component
@Inject
-
@Inject
使用在一個類的屬性上,表示該類需要一個依賴 -
@Inject
使用在一個類的構造方法上,表示由該構造方法提供依賴
假設有個路人Passerby,需要一輛車Car,則可以表示為 Passerby 依賴於 Car。程式碼表示:
Passerby :
public class Passerby {
public Car mCar;
public Passerby(Car car) {
mCar = car;
System.out.println("I'm a Passerby!");
}
}
Car :
public class Car {
@Inject
public Car() {
System.out.println("I'm a Car!");
}
}
當且僅當在 Car
的構造器上使用 @Inject
時,編譯,在 \build\generated\source\apt\debug\com\oliver\test
目錄下自動生成了 Car_Factory.java
檔案:
public final class Car_Factory implements Factory<Car> {
private static final Car_Factory INSTANCE = new Car_Factory();
@Override
public Car get() {
return provideInstance();
}
public static Car provideInstance() {
return new Car();
}
public static Car_Factory create() {
return INSTANCE;
}
public static Car newCar() {
return new Car();
}
}
Car_Factory
實現了 Factory<T>
介面, Factory<T>
繼承至 Provider<T>
介面:
public interface Factory<T> extends Provider<T> {
}
public interface Provider<T> {
/**
* 返回注入的例項
*/
T get();
}
觀察 Car_Factory.java
,可以知道:
- 構造器使用了
@Inject
註解,就會生成類名_Factory
的Factory<T>
實現類。 -
get()
確實返回我們注入的例項 - 自動生成兩個返回
new Car()
的方法,分別是newCar()
和provideInstance()
給 Passerby
的依賴標註 @Inject
註解,再次編譯:
@Inject
public Car mCar;
在\build\generated\source\apt\debug\com\oliver\test
目錄下多了一個 Passerby_MembersInjector
的類:
public final class Passerby_MembersInjector implements MembersInjector<Passerby> {
private final Provider<Car> mCarProvider;
public Passerby_MembersInjector(Provider<Car> mCarProvider) {
this.mCarProvider = mCarProvider;
}
public static MembersInjector<Passerby> create(Provider<Car> mCarProvider) {
return new Passerby_MembersInjector(mCarProvider);
}
@Override
public void injectMembers(Passerby instance) {
injectMCar(instance, mCarProvider.get());
}
public static void injectMCar(Passerby instance, Car mCar) {
instance.mCar = mCar;
}
}
該類實現了 MembersInjector<T>
介面:
public interface MembersInjector<T> {
void injectMembers(T instance);
}
注意 Passerby_MembersInjector
的方法 injectMembers(T instance)
,其引數是 Passerby
型別,也就是說,該方法的使命就是給其引數持有的成員變數賦值,然後外界想辦法獲得這個引數就行了,引數依賴的物件已經在此處完成了注入的過程。
@Override
public void injectMembers(Passerby instance) {
injectMCar(instance, mCarProvider.get());
}
public static void injectMCar(Passerby instance, Car mCar) {
instance.mCar = mCar;
}
另外, Passerby_MembersInjector
多出了一個成員 Provider<Car>
,即一個類的成員變數標註有 @Inject
註解,那麼這個成員就會在生成類中生成相應的 Provider<T>
成員。根據上面對 Car_Factory
的分析,大膽猜測,其實這裡的 Provider<Car>
就是生成的 Car_Factory
。所需依賴也正好在此處注入,即:
instance.mCar = mCarProvider.get();
mCar = new Car();
///////////////////////////// Car_Factory /////////////////////////////
@Override
public Car get() {
return provideInstance();
}
public static Car provideInstance() {
return new Car();
}
上面說到,我們猜測 Provider<Car>
就是生成的 Car_Factory
。那 Provider<Car>
是怎樣賦值的呢?
public Passerby_MembersInjector(Provider<Car> mCarProvider) {
this.mCarProvider = mCarProvider;
}
public static MembersInjector<Passerby> create(
Provider<Car> mCarProvider) {
return new Passerby_MembersInjector(mCarProvider);
}
可以看到,主要是通過 Passerby_MembersInjector.create()
或 new Passerby_MembersInjector()
賦值,其中 create()
又是直接呼叫構造方法的。那這兩個方法是呼叫了哪一個?誰呼叫的?這就要說到另外一個註解了: @Component
。
Dagger
的主要功能時依賴注入,從而達到解耦的目的。所以不會在Xxx_MembersInjector
中直接賦值,這樣的話和 mCar = new Car()
沒什麼區別?所以我猜測,引入了 @Component
是為了達到依賴方和被依賴方不直接耦合的目的。但是,這樣就造成了依賴方和被依賴方都與 @Component
耦合了。所以其實我也不太清楚 @Component
的具體作用。
2019-02-12
@Component
限定了提供依賴的Module
類,如果有過多個Module
都提供該依賴,@Component
的modules
欄位就指定了到底是哪個具體Module
來完成這個依賴的提供。
@Component
@Inject
使用在成員上表示需要依賴物件,使用在構造器上表示提供自身物件。兩者之間需要 @Component
註解作為依賴關係形成的橋樑。
@Component
使用在介面或抽象類上,編譯後在 \build\generated\source\apt\debug\com\oliver\test
目錄下生成一個名稱為 Dagger + 被註解的類名稱
的類。例如:
@Component
public interface Ofo {}
生成類名稱: DaggerOfo
@Component
必須包含至少一個abstract component method
,以下簡稱 CM
,CM
可以隨意命名,但是必須有滿足 Provider
或者 MembesInjector
約束的簽名。
Provider Method :
Provider Method
,以下簡稱 PM
,沒有引數但是有返回值。返回一個 {@link Inject injected}
或 {@link Provides provided}
型別,方法還可以被 @Qualifier
註解標註。也就是說,返回值必須是 被注入型別 或 被提供型別。
-
被注入型別 表示其構造器被
@Inject
標註 -
被提供型別 表示
@Component
包含的@Module
中被@Providers
註解標註的方法的返回值型別
註解 @Module
和 @Providers
是什麼?下面會說到。
MembersInjector Method :
MembersInjector Method
,以下簡稱 MM
,MM
有一個引數,並將依賴項注入每個 {@link Inject}
註解的欄位和傳遞例項的方法,MM
返回 void
, 為方便鏈式呼叫,也可返回 引數型別,。也就是說,引數類中有成員變數被 @Inject
標註,且該成員變數類的構造器也被 @Inject
標註。這樣的話,當 @Compment
實現類【DaggerOfo】
重寫該方法【void inject(MainActivity activity)】
時,就會通過成員變數相應生成的【Passerby_Factory】
構造【Passerby】
例項,賦值給引數【MainActivity】
的成員變數【mPasserby】
。具體如下:
public class Passerby {
@Inject
public Car mCar;
public Passerby(){}
@Inject
public Passerby(Car car) {
mCar = car;
System.out.println("I'm a Passerby!");
}
public void go(){
mCar.go();
}
}
在 MainActivity
中使用:
public class MainActivity extends AppCompatActivity {
@Inject
Passerby mPasserby;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注意,此處注入的引數this不能為null,
DaggerOfo.builder().build().inject(this);
mPasserby.go();
}
}
開始使用 @Component
註解:
@Component
public interface Ofo {
// Passerby getPasserby();
// 使用 MembersInjector Method
void inject(MainActivity activity);
}
在標註了 @Component
註解的類中使用 MM
,生成類如下:
public final class DaggerOfo implements Ofo {
private DaggerOfo(Builder builder) {}
public static Builder builder() {
return new Builder();
}
public static Ofo create() {
return new Builder().build();
}
private Passerby getPasserby() {
return injectPasserby(Passerby_Factory.newPasserby(new Car()));
}
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private Passerby injectPasserby(Passerby instance) {
Passerby_MembersInjector.injectMCar(instance, new Car());
return instance;
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMPasserby(instance, getPasserby());
return instance;
}
public static final class Builder {
private Builder() {}
public Ofo build() {
return new DaggerOfo(this);
}
}
}
可以看到,當我們呼叫 inject()
時,會呼叫到 Passerby_MembersInjector#injectMCar()
:
public static void injectMCar(Passerby instance, Car mCar) {
// 直接賦值,假設傳進來的 instance == null,報空指標就在所難免了
instance.mCar = mCar;
}
呼叫 injectMainActivity(MainActivity)
之後,在層層呼叫,就達到了給成員變數 mPasserby
和 Passerby
的成員變數 mCar
的注入。
現在在 @Component
註解的類中使用 MP
:
@Component
public interface Ofo {
Passerby getPasserby();
// void inject(Passerby passerby);
}
生成類 DaggerOfo
如下:
public final class DaggerOfo implements Ofo {
private DaggerOfo(Builder builder) {}
public static Builder builder() {
return new Builder();
}
public static Ofo create() {
return new Builder().build();
}
@Override
public Passerby getPasserby() {
return injectPasserby(Passerby_Factory.newPasserby(new Car()));
}
private Passerby injectPasserby(Passerby instance) {
Passerby_MembersInjector.injectMCar(instance, new Car());
return instance;
}
public static final class Builder {
private Builder() {}
public Ofo build() {
return new DaggerOfo(this);
}
}
}
可以看到,呼叫 getPasserby()
時會自動生成一個 Passerby
例項,然後給其注入依賴。外界可通過返回值獲取到該例項。
總結
-
@Inject
使用在一個類的屬性上,表示該類需要一個依賴;使用在一個類的構造方法上,表示由該構造方法提供依賴 -
@Component
註解作為依賴關係形成的橋樑,至少包含一個CM
。編譯之後會生成DaggerXxx
類 - 當
CM
型別是MM
,在類【假設為A】
中使用DaggerXxx
,則A
中必須有@Inject
註解標註的成員變數,用於賦值。因為經過上面生成的DaggerOfo
來說,在injectXxx()
中都是這樣模板程式碼:instance.mXxx = Xxx_Factory.newXxx()
,即賦值操作。 - 當
CM
型別是PM
, 在類【假設為A】
中使用DaggerXxx
來獲取需要注入的物件,然後在使用;例如:
Passerby mPasserby = DaggerOfo.builder().build().getPasserby();
mPasserby.go();
相關文章
- Unity DOTS 走馬觀花Unity
- Microservices==>Service Mesh==>Serverless,走馬觀花ROSServer
- 面試周連續劇之走馬觀花面試
- Dagger 2 系列(二) -- 基礎篇:@Inject、@Component
- 走馬
- TextView走馬燈TextView
- 元件間通訊provide和inject元件IDE
- 淺談vue中provide和inject 用法VueIDE
- @bean和@component的理解Bean
- provide/injectIDE
- 純JS實現走馬燈JS
- @Component和@Bean的區別Bean
- 世界AI大會三馬縱論:馬雲樂觀、馬斯克悲觀,馬化騰提了個大危害AI馬斯克
- Dagger2的使用
- Dagger2使用指北
- Spring中@Component和@Configuration的區別Spring
- @Bean和@Component之間的區別?Bean
- provide 和 inject 實現祖先與後代的通訊IDE
- Android so注入(inject)和Hook技術學習(二)——GAndroidHook
- [Vue] Provide and Inject Global StorageVueIDE
- HTB靶場之-inject
- 元件通訊 provide inject元件IDE
- JAVA CDI @Inject基本用法Java
- 當Dagger2撞上ViewModelView
- Dagger2融合篇(三)
- 劍走偏鋒之Vue元件通訊(二)——利用provide / inject屬性構建全域性狀態管理Vue元件IDE
- 用slot和component實現表單共用
- React.createClass和extends Component的區別React
- vue 3 學習筆記 (八)——provide 和 inject 用法及原理Vue筆記IDE
- Vue.js 原始碼學習五 —— provide 和 inject 學習Vue.js原始碼IDE
- 052、走馬川行奉送封大夫出師西征
- 亞馬遜如何趕走煩人的跟賣亞馬遜
- 使用 Flutter 實現一個走馬燈佈局Flutter
- Element-Ui元件(四十二)Carousel 走馬燈UI元件
- 聽說你還不會用Dagger2?Dagger2 For Android最佳實踐教程Android
- Dagger2基礎篇(一)
- Dagger2進階篇(二)
- sidecar-inject程式碼分析IDE