Dagger란?
Dagger
는 자바 안드로이드에서 사용 가능한 정적 컴파일타임 의존성주입 프레임워크 입니다. Annotation Proccessor
를 통해 컴파일 타임에 어노테이션을 읽고 의존성 주입에 필요한 클래스들을 생성합니다. 어노테이션 처리를 컴파일 시점에 별도의 프로세서에서 처리하므로 성능이 향상되고, 클래스 Reflection을 사용하지 않으므로 Runtime Exception 발생을 막으며 Proguard 설정의 번거로움에서 벗어날 수 있습니다.
Module
Module에서 하는 역할은 @Provides
,@Binds
를 통해 주입할 클래스의 인스턴스를 생성합니다.
메소드의 반환 타입을 통해서 주입할 객체를 정하며, 반환타입이 같을 경우 @Qualifier
를 통해 주입할 객체를 지정할 수 있습니다.
@Module
class ComputerModule {
@Provides
fun provideCpu(): Cpu {
return M1Cpu()
}
@Provides
fun provideRam(): Ram {
return Ram8G()
}
}
@Module
abstract class BindsComputerModule {
@Binds
abstract fun bindCpu(i7Cpu: I7Cpu): Cpu
}
@Provides vs @Binds
@Binds
는@Provides
에 비해 컴파일 시점에 생성되는 코드가 줄어들고 효율적으로 사용할 수 있습니다.
@Binds
를 사용하면 불필요한 모듈 Factory 혹은 Builder의 생성을 하지 않고 코드의 라인 수를 줄일 수 있으므로 훨씬 효율적으로 주입할 수 있습니다.
대신 제약조건이 있는데, 추상클래스, 추상메소드여야 하는점이고 매개변수에 주입 가능한 Interface의 구현체를 매개변수로 가져야 합니다.
https://medium.com/mobile-app-development-publication/dagger-2-binds-vs-provides-cbf3c10511b5
Component
Component
의 역할은 연결된 Module에서 생성된 인스턴스를 @Inject
를 통해서 요청하는 객체에 Component가 인스턴스를 주입합니다.
주입 메소드의 유형에는 두 가지가 존재합니다.
1. Provision Method
Provision 메소드
유형은 인자(매개변수)가 없고, Module이 injection 시킬 객체를 리턴타입으로 가집니다.
주입받을 객체에서는 생성자에 @Inject
어노테이션을 달아주어야 합니다.
2. Member-Injection Method
의존성을 주입시킬 객체를 메서드의 파라미터로 넘기는 방식으로, Member-Injection 메소드
를 호출하면 인자(매개변수)로 받은 타겟 클래스 내부 @Inject
가 붙은 필드에 객체를 주입합니다
@Component.Builder, @Component.Factory
컴포넌트를 객체화하여 생성하기위한 어노테이션입니다.
둘다 선언되지 않았다면 Default Builder 혹은 Factory가 생성되고 Builder와 Factory 두 가지 동시에 선언할 수 없습니다.
Builder나 Factory는 Component 어노테이션의 modules, dependencies에 선언된 모든 모듈들을 매개변수로 포함하고 있어야 합니다.
차이점은 Builder에서는 모듈들을 포함하는 Setter메소드들과 Component를 반환하는 추상메소드(build() 메소드)를 포함해야하고, Factory에서는 모듈들을 포함하며 Component를 반환하는 하나의 추상메소드만 존재해야 합니다.
@BindsInstance
@BindsInstance
어노테이션을 통해서 외부에서 생성된 인스턴스를 사용할 수 있습니다. Builder나 Factory의 메소드의 매개변수를 통해 넘겨줌으로써 컴포넌트가 해당 인스턴스를 바인드하게 됩니다.
가장 많이 받아오는 예는 context를 받아오는 것입니다.
@Component(modules = [ComputerModule::class])
interface ComputerComponent {
fun getComputerB(): ComputerB // Provision Method
fun inject(computerA: ComputerA) // Member-Injection Method
@Component.Builder
interface Builder {
fun computerModule(computerModule: ComputerModule): Builder
fun application(@BindsInstance context: Context): Builder
fun build(): ComputerComponent
}
@Component.Factory
interface Factory {
fun create(
@BindsInstance context: Context, computerModule: ComputerModule
): ComputerComponent
}
}
Inject
의존성 주입을 요청합니다. @Inject
를 통해서 주입을 요청하면 Component가 Module로 부터 인스턴스를 넘겨줍니다.
변수에 달면 Field Injection
을 수행하고,
생성자에 달면 Constructor Injection
을 수행합니다.
class ComputerA { // Field Injection
@Inject
lateinit var cpu: Cpu
@Inject
lateinit var ram: Ram
}
class ComputerB @Inject constructor(val cpu: Cpu, val ram: Ram) // Constructor Injection