Image
Android/Dependency Injection

[Dagger2] 8. Scope를 이용한 객체 재사용 범위 설정

예제 링크 : https://github.com/seyoungcho2/Dagger2Example

이 글은 예제7,8,9과 함께 한다. 


Scope란?

Dagger2의 역할은 외부에서 의존성을 주입해주는 것이다. 여기서 문제점이 생긴다. 외부(Container)에서 제공하는 인스턴스들이 한 번만 생성되어도 되는데 호출할 때마다 생성된다면 불필요한 메모리 사용이 생긴다.

 

Dagger2에서는 이를 해결하기 위해 Scope Annotation을 이용해 같은 범위(Scope)의 내에서 객체들을 관리하게 된다. Scope Annotation이 적용된 Provider은 범위(Scope) 내에서 한 번만 객체를 생성한다. 

Dagger에서는 Scope Annotation을 이용해 한 번 생성된 객체가 재사용되는 범위(Scope)를 관리한다.

 

예를 들어 다음과 같은 Application class가 있다고 해보자

class Application()

 

Scope 적용이 안되었을 경우(예제7)

이러한 Application을 제공하는 Component와 Module을 다음과 같이 설정한다.

@Component(modules = [AppModule::class])
interface AppComponent {
    fun getApplication() : Application
}
@Module
class AppModule {
    @Provides
    fun providesApplication() = Application()
}

이렇게 할 경우 이 Component로부터 getApplication()을 이용해 두 개의 Application을 받아왔을 때, 두 Application 에 대한 동일성 연산(===)은 false가 나온다. getApplication을 할 때마다 Application이 생성되기 때문이다.

fun main() {
    val appComponent: AppComponent = DaggerAppComponent.create()

    val application1 = appComponent.getApplication()
    val application2 = appComponent.getApplication()

    println(application1 === application2) // false
}

 

Scope 적용이 되었을 경우(예제8)

Component와 Provider에 다음과 같이 Singleton Scope를 적용한다.

*여기서의 Singleton Scope는 객체가 재사용되는 범위를 설정하기 위한 것이다. Process가 살아있는 동안 하나의 인스턴스만 생성한다는 원래의 Singleton 개념이 아니다. 다음 예제에서 자세히 다룬다.

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun getApplication() : Application
}
@Module
class AppModule {
    @Singleton
    @Provides
    fun providesApplication() = Application()
}

이렇게 할 경우 이 Component로부터 두 개의 Application에 대한 동일성 연산(===)은 true가 나온다.

 

fun main() {
    val appComponent: AppComponent = DaggerAppComponent.create()

    val application1 = appComponent.getApplication()
    val application2 = appComponent.getApplication()

    println(application1 === application2) // true
}

 

 

Singleton Scope는 Singleton을 위한 것이 아니다.

위에 나오는 Singleton Scope는 이름 때문에 많은 사람들이 헷갈려한다. 하지만, Singleton Scope는 Singleton 객체를 만들기 위한 것이 아니라 단순히 @Scope Annotation이 적용된 Annotation Processor일 뿐이다.

 

먼저 내부를 보면 Singleton Scope는 다음과 같이 설정되어 있다.

@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

이러한 Singleton 대신 다른 이름의 Scope를 만들어 쓴다면 어떨까? 아래에서 CustomScope를 만들어 테스트한다.

 

CustomScope만들기(예제9)

먼저 위 Singleton annotation과 같은 역할을 하는 Kotlin annotation class를 만든다.

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class CustomScope()

자 이제 AppComponent, AppModule에 우리가 만든 CustomScope를 적용한다.

@CustomScope
@Component(modules = [AppModule::class])
interface AppComponent {
    fun getApplication() : Application
}
@Module
class AppModule {
    @CustomScope
    @Provides
    fun providesApplication() = Application()
}

자 이제 이 Scope동안은 하나의 Application만이 생성된다. 따라서 아래의 코드가 돌아갈 경우 동등성 연산에서 true를 반환한다.

fun main() {
    val appComponent: AppComponent = DaggerAppComponent.create()

    val application1 = appComponent.getApplication()
    val application2 = appComponent.getApplication()

    println(application1 === application2)// true
}

 

Scope는 객체가 재사용되는 범위만을 가리킬 뿐이다.

 

반응형

 

이 글의 저작권은 '조세영의 Kotlin World' 에 있습니다. 글, 이미지 무단 재배포 및 변경을 금지합니다.

 

 

Kotlin, Android, Spring 사용자 오픈 카톡

오셔서 궁금한 점을 질문해보세요!
비밀번호 : kotlin22

open.kakao.com