안녕하세요 남갯입니다.
https://cmcmcmcm.blog/2017/07/27/didependency-injection-%ec%99%80-dagger2/
대거의 annotation 4가지
@Compenent: 실제 의존성 주입이 구현될 인터페이스나 추상클래스에 사용되는 annotation
@Module : 의존성 관계를 설정하는 클래스에 사용되는 annotation
@Provides : 객체를 제공하기 위한 메서드에 달아주는 annotation
@Inject : DI를 진행할 멤버변수와 생성자에 달아준다.
@Module
public class CoffeeMakerModule {
@Provides
Heater provideHeater(){
return new A_Heater();
}
@Provides
Pump providePump(Heater heater){
return new A_Pump(heater);
}
}
모듈 자체와 provides는 component 클래스에서 실제 코드가 주입 생성될떄 영향을 준다
@Component(modules = CoffeeMakerModule.class)
public interface CoffeeComponent {
//provision method
CoffeeMaker make();
//member-injection method
void inject(CoffeeMaker coffeeMaker);
}
찰스 - 아키텍쳐를 알아야 앱이 보인다.
모듈
1. Module 내부에 Provides Annotation을 이용할 시
중복되는 반환타입을 선언하면 안된다.
2. include키워드를 통해 모듈을 추가 가능
* 단 이때도 중복되는 반환타입이 있으면 안된다.
컴포넌트
@Component(modules = [MyModule::class])
를 통해 모듈을 주입
component 속성은 두가지가 있다
modules 와 dependencies 가 있다.
컴포넌트 메서드
- 프로비전 메서드
@Component(modules = [MyModule::class])
interface MyComponent {
fun getClassB() : ClassB
}
위와 같이 매개 변수는 없고 반환타입을 가지는 메소드를 프로비전 메서드라고 한다.
- 멤버 인젝션 메서드
@Component(modules = [MyModule::class])
interface MyComponent {
fun injectSomeType(classB: ClassB)
}
하나의 매개변수를 갖는 메서드를 멤버 인젝션 메서드라고 부른다.
- 의존성 주입
세가지를 통해 의존성 주입이 가능하다.
-필드주입
-생성자주입
-매서드 주입
-상속 클래스의 주입
상속에서의 클래스에서는 각자 클래스에 각각 주입된다.
- 컴포넌트 빌더,팩토리
컴포넌트의 빌더와 팩토리는 둘중 하나라도 존재하지 않을경우 자동으로 빌더를 생성한다.
@Component(modules = [MyModule::class])
interface MyComponent {
fun getString() : String
fun getClassB() : ClassB
fun injectSomeType(classB: ClassB)
@Component.Builder
interface Builder{
fun setMyModule(myModule: MyModule) : Builder
fun build() : MyComponent
}
}
내부적으로는 위와 같이 생성된다.
직접 구현을 통해 생성한다면 아래의 조건을 따라야한다.
컴포넌트 빌더를 만드는 조건
1. @Component.Builder 어노테이션은 컴포넌트 타입 내에 선언되어야 한다.
2. 반드시 매개변수를 갖지 않고 컴포넌트 타입 또는 컴포넌트의 슈퍼타입을 반환하는 추상 메서드를 하나 포함해야한다. 이런것을 빌드 메서드라고한다. (위의 코드에서 build 메소드)
3. 빌드 메서드를 제외한 나머지는 세터 메서드라고 한다.
4. @Component 어노테이션에 modules, dependencies 선언된 요소드른 세터 메서드로 선언 해야한다.
5. 세터 메서드는 반드시 하나의 매개변수만 가져야하며 반환형으로는 void ,빌더 또는 빌더의 슈퍼타입
6. 세터 메서드에 @BindsInstance를 붙이면 해당 컴포넌트에 인스턴스를 넘겨 바인드 시킨다.
컴포넌트 팩토리를 만드는 조건
1. @Component.Factory 어노테이션은 컴포넌트 타입 내에 선언되어야한다.
2. 컴포넌트 팩토리는 컴포넌트 타입 또는 컴포넌트의 슈퍼타입을 반환하는 하나의 추상메서드만 존재해야한다..
3. 팩토리 메서드에는 @Component 어노테이션에 modules , dependencies 로 지정된 속성들을 반드시 매개변수로 만가져야 한다.
4. 메서드에 @BindInstance 어노테이션이 붙은 매개변수는 해당 컴포넌트에 인스턴스를 넘겨 바인드 시킨다. 생성되는 컴포넌트 타입에는 factory()라는 정적 메서드를 갖는데, 팩토리 인스턴스를 반환한다. 이 팩토리 컴포넌트로 초기화 할 수 있다.
lazy 주입, provider주입
객체가 초기화하는데, 시간이 필요하다면 lazy 주입을 고려해 볼 수 있다.
바인드된 T 타입을 제너릭으로 갖는 Lazy<T> 타입을 만들면 된다.
Lazy 주입
@Inject
Lazy<Integer> lazy
@Inject
Lazy<Integer> lazy
이런식으로 inject밑에 타입을 Lazy 타입으로 받을 수 있다.
Provider주입
매번 새로운 객체를 주입 받고 싶다면 Provider<T>를 통해 가능하다.
Prodiver<T>의 get() 메서드를 호출할때 마다 새로운 객체를 제공 받는다.
*단, 컴포넌트가 @Singleton 과 같은 특정 범위로 지정되었다면 Provider<T>를 사용한다고 하더라도
바인드된 의존성은 싱글톤으로 관리되어 같은 인스턴스를 제공받는다.
- 한정자 지정
@Named 키워드를 사용해서 반환타입이 같을 경우
@Provides
@Named("hello")
fun provideHello() : String{
return "hello"
}
@Provides
@Named("world")
fun provideWorld() : String{
return "world"
}
위와같이 named를 이용해서 사용해야한다.
사용자 정의 한정자 만들기
@Qualifier 키워드를 통해 직접 한정자를 만들 수 있다.
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Hello{}
이후 @Hello키워드를 통해 주입 가능하다
@Provides
@Hello
String provideHello(){ return "Hello"}
'IT > 안드로이드 관련' 카테고리의 다른 글
[안드로이드] Clean Architecture (5) | 2020.06.25 |
---|---|
[dagger] 대거 - 2 정리용 (0) | 2020.05.19 |
[안드로이드] 전이 의존성 exclude transitive dependency (0) | 2020.03.19 |
[안드로이드] 파일과 MediaStore 싱크 맞추기 (0) | 2020.03.13 |
[안드로이드] api와 implementation 차이 (0) | 2020.02.28 |