오늘은 Dependency Injection에 대한 지난 글에 이어서,
Dagger를 통해서 어떻게 이를 구현하는지 정리해 보려고 합니다.
혹시 이전 글을 읽지 못하신 분들은아래 글의 링크를 참조해 주세요.
Dependency Injection(DI)에 대해서 알아보자
Dagger1은 Retrofit등 유명한 라이브러리를 개발한 Square사의 작품이구요.
현재 사용되는 Dagger2는 구글에서 포크하여 개발하고 있습니다.
무조건적인 신뢰는 좋지 않습니다만, 이들 회사의 네임밸류와 포트폴리오 만으로도,
라이브러리에 대한 믿음이 생기는 건 어쩔수가 없네요.
그럼 Dagger를 구현하는 방법에 대해서 정리해 보도록 하겠습니다.
1. dagger2를 통한 구현준비
1-1. 라이브러리 Implement
라이브러리를 가져오기 위해서는 아래와 같이 app레벨의 dependencies를 추가해 주면 되는데요.
버전은 계속 바뀌게 되므로 아래의 공식 깃허브를 참조해 주시면 좋습니다.
https://github.com/google/dagger/releases
이제 라이브러리를 사용할 준비가 되었으므로,
간단히 구현해 보기 위해, 객체를 만들기 위한 클래스들을 준비해 보도록 하겠습니다.
1-2. Car클래스와 Tire클래스
Dependency Injection의 개념들을 Car클래스를 이용해서, 구현해 보려고 하는데요.
Car에는 Tire가 필요하므로 Car와 Tire 두개의 클래스를 만들었습니다.
(물론 실제로는 Tire외엥도 더 많은 부품이 필요하지만 말이지요.)
Tire클래스는 간단히 아래와 같습니다.
이제 Class들이 준비가 되었으니 작업을 해 보도록 하겠습니다.
2. Scope
Dagger를 정복하기 전에 알아야 할 것 중 하나가 Scope 입니다.
범위라는 뜻인데요. 정의한 변수가 얼마만큼 영향이 가거나 살아있을지를 정의하는 것 이지요.
Dagger에서는 이 스코프를 Annotation을 이용해서 정의합니다.
아직 Component에 대해서 배우지는 않았는데요.
Component는 Scope를 참조해서 객체를 생성해서 전달해 준다는 점만 여기서는 알고 가겠습니다.
2-1. @Singleton
Singleton이라는 것이 앱내에서 하나의 객체만 존재하며 그것을 계속 이용한다는 의미로 보통 쓰이는데요.
Dagger에서 이 Singleton애노테이션을 붙인다면,
생성한 객체를 유지시켜 줍니다. DI(Dependency Injection)의 언어로 말하자면, Dependency를 유지하고 있는 것 이지요.
Singleton 애노테이션이 필요한 예로는, Retrofit객체를 들 수 있겠네요.
만약 아무런 Annotation이 없다면 Component는 필요할 때 마다 객체를 생성시킵니다.
2-2.
3. Component
AppComponent는 앱의 전체 주기동안 필요로하는 Component 입니다.
보통 Scope는 Singleton로 사용하게 되겠지요.
특정 Activity 에서만 사용하기 보다는,
Retrofit의 객체처럼 여러 Activity에서 동일하게 사용되는 객체의 경우 유용하겠습니다.
3-1. AppComponent의 구현
Application에서 DaggerApplication()을 상속받습니다.
그럼 구현해야 할 함수가 하나 나오는데요.
3-2. SubComponent
AppComponent와는 다르게, 특정 액티비티나 주기동안에만
필요한 컴포넌트 입니다.
그렇다고 동작방식이 크게 다른 것은 아닙니다.
특정 주기에만 필요한 Component의 경우는 해당 Component에서만 활용할 수 있도록 해야겠습니다.
2. Dagger 구현 방법
이전의 Dependency Injection에 대한 글(https://developer88.tistory.com/172)을 읽어보셨다면,
Dagger(혹은 Dependency Injection라이브러리)를 사용하는 이유가 필요한 부품(객체)의 생성을 외부에 맡겨서
원하는 곳에 주입(Inject)하는 것을 효율적으로 하기 위함임을 아셨을 텐데요.
다시 한번 차에 비교해보면, 자동차를 생산하는데 타이어 생산은 외부에 주문해서 받아서,
원하는 곳에 장착하는 것이지요.
이러한 개념을 Dagger는 자동차에 필요한 타이어를 생산해 전달해 주는 Component가 있고,
타이어를 생산해 이를 Inject(주입) 해주는 개념으로서 접근합니다.
생각보다 그리 어렵지 않아 보이는데요.
그럼 이를 코드로 구현하는 방법은 어떨까요?
Dagger를 구현하는 방법은 다양하지만 크게 두가지를 생각해 볼 수 있는데요.
클래스의 생성자에서 Injection(주입)하는 방법과
module을 만들어서 객체생성을 주관하여 provides 애노테이션을 사용하는 방법이 있습니다.
하나씩 정리해 보도록 하겠습니다.
3. 생성자에 Injection하여 구현하는 방법
밑에서 소개하는 module을 이용하는 방법보다는 코드량도 적고 구현방법도 상대적으로 쉬우므로,
가능하다면 이 방법을 통해 구현하는 것이 좋을 것 같습니다.
3-1. 생성자에 Injection Annotation
Dagger에서는 '@Inject'를 통해서 Dependency를 요청한다는 표시를 남기는데요
Inject애노테이션은 Constructor(생성자), Field, method에 남길 수 있습니다.
여기서는 생성자에 남겨서, Dependency를 구현하는 방법을 정리해 보겠습니다.
생성자에 사용할 경우는 하나의 생성자에만 표시할 수 있다는 조건이 있는데요.
생성자의 인자들이 Dependency라고 보면 되겠습니다.
아래와 같이 생성자에 Inject애노테이션을 붙이면
Dagger는 여기에 들어올 객체를 생성하는 방법을 알고 있습니다.
Tire클래스의 생성자에도 Dependency를 요청하기 위해 Inject애노테이션을 붙여줍니다.
중요한 것은 Dependency를 요청하는 곳에,
Dependency그래프를 그리는 Dagger에게 표시해 두었다는 점 입니다.
3-2. Component
이제 필요한 것이 바로 Component입니다.
Inject애노테이션을 표시한 곳에서 대거는 어떻게 객체를 생산하는지 알게 될 것이구요.
완성된 객체를 전달하는 Component가 필요한데요.
아래와 같이 만들어 주면 됩니다.
생성된 객체를 얻어갈 수 있는 interface의 메소드를 만들어 줄 뿐이지요.
이제 마지막으로 중요한 것이 남았는데요.
바로 Annotation Processiong 이라고 하는 것 입니다.
3-3. Annotation Processiong
위에서 붙인 애노테이션을 기준으로 대거가 코드를 생성해 주는데요.
Build> Make Project를 해 보면 됩니다.
3-4. 객체 이용해 보기
저희는 interface인 컴포넌트를 구현한 적이 없는데요.
이것은 Dagger가 구현해 줍니다.
아래와 같이 Dagger를 붙인 DaggerCarComponent를 타이핑해보면,
놀랍게도 생성되어 있는 것을 알 수 있습니다.
이를 이용해 component생성후 자동차 객체를 얻어올 수 있습니다.
run 해보면 아래와 같이 정상적으로 객체의 멤버 메소드가 동작하는 것을 볼 수 있습니다.
자동차와 타이어라는 매우 간단한 예지만,
Dependency Injection을 구현해보았네요.
객체 생성해서 넘겨줄 곳에 Inject애노테이션을 붙여준 것 만으로도 쉽게 구현할 수 있었네요.
아래에서는 Module을 사용해 구현하는 방법도 정리해 보도록 하겠습니다.
4. field에 Injection하는 방법
5. method에 Injection하는 방법
4. Module을 사용하여 객체를 생성하는 방법
4-1. Module과 Provide
이 구현 방법에 있어서 module은 디펜던시를 제공해주는 중요한 역할을 하는데요.
위에서는 생성자에서 @Inject애노테이션을 보고 Dagger가 객체를 생성하는 방법을 알았다면,
이 방법에서는, Module을 만들고, 이 모듈이 Component에 객체를 제공합니다.
module을 필요한 객체들을 만들어서 저장하고 있는 곳이라고 보면 되겠습니다.
자동차(Car)를 만드는 데 타이어가 필요하므로 여기서는 타이어를 생성해야 겠습니다.
CarModule이라는 클래스를 만들고 애노테이션으로 @Module을 사용합니다.
객체를 생성할 클래스들에는 @Provides애노테이션을 붙여줍니다.
2-3. Component
각 모듈(Module)들에서 제공받은 객체들을 필요로 하는 곳(@inject애노테이션이 붙은 곳)에 주입(Inject)하는 역할 을 합니다.
따라서 Injector라고 부르기도 합니다.
Component는 아래와 같이 interface로 구현 하구요.
애노테이션을 Component로 붙여주고, 사용할 모듈클래스를 적어줍니다.
2-4. Annotation Processiong
위에서 해봤었던 부분인데요.
Build>Make Project해서 Annotation Processiong을 거칩니다.
2-5. MainActivity에서 Inject로 객체 주입하기
이제 MainActivity에서 위에서 만든 컴포넌트 객체를 만들고,
그 객체를 이용해 inject를 할텐데요.
아래 코드를 보시면 DaggerCarComponent라는 클래스는 저희가 만든적이 없는데 사용되어 있습니다.
대거가 위의 Annotation들을 참조하여 만든 코드인데요.
여기에 사용한 carModule을 넣어주고 build를 해주면 컴포넌트 객체가 생성되구요.
여기에 inject메소드를 사용하면 됩니다.
마지막으로 유심히 볼 것은,
@Inject애노테이션을 붙인 mCar변수 입니다.
@Inject애노테이션을 붙이면, 주입받는 대상이 되는 것이지요.
빌드를 돌려보면, 정상적으로 객체가 만들어져서 drive메소드가 동작한 것을 알 수 있습니다.
이렇게 해서 Dependency Injection에 대해서 이해하고,
Dagger로 구현해 보았습니다.
좀 더 추가적인 정보는 아래의 Dagger Guide를 참조해 보시면 될 것 같네요.
https://dagger.dev/users-guide.html
'Android 개발 > Hilt, Koin, DI(Dependency Injection)' 카테고리의 다른 글
HILT 에 대해서 정리해 보겠습니다. # DI Dependency Injection (3) | 2022.09.16 |
---|---|
KOIN을 이용한 Dependency Injection (DI) 구현하기 (0) | 2020.01.06 |
Dependency Injection(DI)에 대해서 알아보자 (0) | 2019.12.28 |
댓글