CHAPTER 6. Dependency injection
DI yourself
์์กด์ฑ ์ฃผ์ ์ ์ ์๋ ค์ง ๋์์ธ ํจํด์ด๋ค. ์ฐ๋ฆฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ฑ ์์๋ฅผ ์ดํด ๋ณด๋๋ก ํ์. ์ด ๊ตฌ์ฑ ์์๋ ์ฑ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ์ ๊ณตํ๋ ์ผ๋ถ ๊ธฐ๋ฅ์ ํ์๋ก ํ ์ ์๋ค. (์๋น์ค ๋ผ๊ณ ๋ถ๋ฅด๋๋ก ํ์). ๊ทธ๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ข ์์ฑ์ด๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ์ด๋ค. ๊ตฌ์ฑ ์์๊ฐ ์ข ์์ฑ์ ๋ง๋ค๋๋กํ๋ ๋์ , ํ๋ ์ ์ํฌ๋์ด๋ฅผ ์์ฑํ์ฌ ๊ตฌ์ฑ ์์์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ "์ ์ด ๋ฐ์ (inversion of control)"์ด๋ผ๊ณ ํ๋ค.
์ฌ๊ธฐ์๋ ๋ช ๊ฐ์ง ํฅ๋ฏธ๋ก์ด ๊ธฐ๋ฅ์ด ์๋ค. โข ๊ทธ๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ์ ๋งํ๊ณ ์ํ๋ ๊ณณ์ ๋งํจ์ผ๋ก์จ ์ฝ๊ฒ ๊ฐ๋ฐํ ์ ์๋ค. โข ์์กด์ฑ์ ๋ชจ์ ๊ฐ์ฒด๋ก ๋์ฒดํ์ฌ ์ฝ๊ฒ ํ ์คํธ ํ ์ ์๋ค. โข ๊ตฌํ์ ๋ฐ๊พธ๋ฉด ์ฝ๊ฒ ๊ตฌ์ฑ ํ ์ ์๋ค.
์ด๊ฒ์ ์๋ฒ ์ธก์์ ๊ด๋ฒ์ํ๊ฒ ์ฌ์ฉ๋๋ ๊ฐ๋ ์ด์ง๋ง AngularJS 1.x๋ ํ๋ก ํธ ์๋ ์ธก์์ ์ฒ์์ผ๋ก ์ฌ์ฉํ๋ ๊ฐ๋ ์ค ํ๋์ด๋ค.
Easy to develop
์์กด์ฑ ์ฝ์ ์ ์ฌ์ฉํ๋ ค๋ฉด ๋ช ๊ฐ์ง๊ฐ ํ์ํ๋ค. โข ์ข ์์ฑ์ ๋ฑ๋กํ์ฌ ๋ค๋ฅธ ๊ตฌ์ฑ ์์ / ์๋น์ค์ ์ฃผ์ ํ ์์๊ฒํ๋ ๋ฐฉ๋ฒ โข ํ์ฌ ๊ตฌ์ฑ ์์ / ์๋น์ค์์ ์ด๋ค ์ข ์์ฑ์ด ํ์ํ์ง ์ ์ธํ๋ ๋ฐฉ๋ฒ
ํ๋ ์ ์ํฌ๋ ๋๋จธ์ง ์์ ์ ์ํํ๋ค. ์ฐ๋ฆฌ๊ฐ ์ปดํฌ๋ํธ์ ์์กด์ฑ์ ์ ์ธ ํ ๋, ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์ฐพ์ ์ ์๋ค๋ฉด ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์กฐ์ฌ ํ ๊ฒ์ด๊ณ , ์์กด์ฑ์ ์ธ์คํด์ค๋ฅผ ์ป๊ฑฐ๋, ์์กด์ฑ์ ์ธ์คํด์ค๋ฅผ ์์ฑ ํ ๊ฒ์ด๋ฉฐ ์ค์ ๋ก ์ปดํฌ๋ํธ์ ์์กด์ฑ์ด ์ฃผ์ ๋ ๊ฒ์ด๋ค.
์์กด์ฑ์ Angular๊ฐ ์ ๊ณตํ๋ ์๋น์ค์ด๊ฑฐ๋ ์ฐ๋ฆฌ๊ฐ ์ค์ค๋ก ์์ฑํ ์๋น์ค ์ผ ์ ์์ต๋๋ค.
์ด๋ฏธ ๋๋ฃ ์ค ํ ๋ช ์ด ์์ฑํ ApiServiceservice๋ฅผ ์๋ก ๋ค์ด ๋ณด์. ๊ทธ๋ ๊ฒ์ผ๋ฅธ ์น๊ตฌ์ด๊ธฐ ๋๋ฌธ์ ๋น ๋ฐฐ์ด์ ๋ฐํํ๋ get ๋ฉ์๋๋ฅผ ์์ฑ๋ง ํ์๋ค. ํด๋น ์๋น์ค๊ฐ ๋ฐฑ์๋ API์ ํต์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๊ฒ์ผ๋ก ์ด๋ฏธ ์ถ์ธก ํ ์ ์๋ค.
export class ApiService {
get(path) {
// todo: call the backend API
}
}
TypeScript๋ฅผ ์ฌ์ฉํ๋ฉด ๊ตฌ์ฑ ์์ ๋ ์๋น์ค์ ๋ํ ์ข ์์ฑ์ ์ ์ธํ๊ธฐ ์ฝ๋ค. ApiService๋ฅผ ์ฌ์ฉํ๋ RaceService๋ฅผ ์์ฑํ๋ ค๊ณ ํ๋ค๊ณ ๊ฐ์ ํด ๋ณด์.
import { ApiService } from './api.service';
export class RaceService {
constructor(private apiService: ApiService) {
}
}
Angular๋ ApiService ์๋น์ค๋ฅผ ๊ฐ์ ธ ์์ ์์ฑ์์ ์ฝ์ ๋๊ณ RaceService๊ฐ ํ์ํ ๋ ์์ฑ์๊ฐ ํธ์ถ๋๊ณ ApiService ํ๋๊ฐ ApiService ์๋น์ค๋ฅผ ์ฐธ์กฐํ๊ฒ๋๋ค. ์ด์ ApiService ์๋น์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฑ์๋์ ํธ์ถ ํ ๋ฉ์๋ ๋ชฉ๋ก ()์ ์๋น์ค์ ์ถ๊ฐ ํ ์ ์๋ค.
import { ApiService } from './api.service';
export class RaceService {
constructor(private apiService: ApiService) {
}
list() {
return this.apiService.get('/races');
}
}
Angular 2 ์์๋ ์๋น์ค ์์ฒด์ ์์กด์ฑ์ด ์์์ ์๋ฆฌ๋ ค๋ฉด ํด๋์ค ๋ฐ์ฝ๋ ์ดํฐ('@Injectable()')๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค.
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
@Injectable()
export class RaceService {
constructor(private apiService: ApiService) {
}
list() {
return this.apiService.get('/races');
}
}
์ด๊ฒ์ ํ๊ธฐ ์ํ ์ฌ์ด ๋ฐฉ๋ฒ์ ์์์ ๋ณธ @NgModule ๋ฐ์ฝ๋ ์ดํฐ์ providers ์์ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PonyRacerAppComponent } from './app.component';
import { ApiService } from './services/api.service';
@NgModule({
imports: [BrowserModule],
declarations: [PonyRacerAppComponent],
providers: [
ApiService
],
bootstrap: [PonyRacerAppComponent]
})
export class AppModule {
}
์ด์ ReceService ๋ฅผ ๋ค๋ฅธ ์๋น์ค ๋ ๊ตฌ์ฑ ์์์ ์ฃผ์ ํ ์์๊ฒํ๋ ค๋ฉด ๋ฑ๋กํด์ผํ๋ค.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PonyRacerAppComponent } from './app.component';
import { RaceService } from './services/race.service';
import { ApiService } from './services/api.service';
@NgModule({
imports: [BrowserModule],
declarations: [PonyRacerAppComponent],
providers: [
RaceService,
ApiService
],
bootstrap: [PonyRacerAppComponent]
})
export class AppModule {
}
์ฐ๋ฆฌ๋ ์ฐ๋ฆฌ๊ฐ ์ํ ๋๋ง๋ค ์๋ก์ด ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค. PonyRacerAppComponent ๊ตฌ์ฑ ์์์์ ํ ์คํธ ํด ๋ณด๋๋ก ํ์.
import { Component } from '@angular/core';
import { RaceService } from './services/race.service';
@Component({
selector: 'ponyracer-app',
template: `<h1>PonyRacer</h1>
<p>{{list()}}</p>`
})
export class PonyRacerAppComponent {
// add a constructor with RaceService
constructor(private raceService: RaceService) {
}
list() {
return this.raceService.list();
}
}
์ฐ๋ฆฌ์ ๊ฒ์ผ๋ฅธ ๋๋ฃ๊ฐ ApiService์ get ๋ฉ์๋์์ ๋น ๋ฐฐ์ด์ ๋ฐํ ํ์ผ๋ฏ๋ก list () ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ค๊ณ ํ๋ฉด ์๋ฌด ๊ฒ๋ ์ป์ ์ ์๋ค.
Easy to Configure
๋ค์ ์ฅ์์ ์ข ์์ฑ ์ฃผ์ ์ผ๋ก ์ธํ ํ ์คํธ ๊ฐ๋ฅ์ฑ ์ด์ ์ผ๋ก ๋ค์๊ฐ ๊ฒ ์ง๋ง ๊ตฌ์ฑ ๋ฌธ์ ๋ฅผ ์ดํด๋ณผ ์ ์๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ์กด์ฌํ์ง ์๋ ๋ฐฑ์๋๋ฅผ ํธ์ถํ๋ ค๊ณ ํ๋ค. ์ด์ฉ๋ฉด ๋ฐฑ์๋ ํ์ด ์์ง ์ค๋น๊ฐ๋์ง ์์๊ฑฐ๋ ๋์ค์ํ๊ณ ์ถ์ ์๋ ์๋ค. ์ด์จ๋ ์ฐ๋ฆฌ๋ ๊ฐ์ง ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PonyRacerAppComponent } from './app.component';
import { RaceService } from './services/race.service';
import { ApiService } from './services/api.service';
@NgModule({
imports: [BrowserModule],
declarations: [PonyRacerAppComponent],
providers: [
RaceService,
ApiService
],
bootstrap: [PonyRacerAppComponent]
})
export class AppModule {
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PonyRacerAppComponent } from './app.component';
import { RaceService } from './services/race.service';
import { ApiService } from './services/api.service';
@NgModule({
imports: [BrowserModule],
declarations: [PonyRacerAppComponent],
bootstrap: [PonyRacerAppComponent],
providers: [
{ provide: RaceService, useClass: RaceService },
{ provide: ApiService, useClass: ApiService }
]
})
export class AppModule {
}
์ธ์ ํฐ๋ ํ ํฐ (RaceService ์ ํ)๊ณผ RaceService ํด๋์ค ์ฌ์ด์ ์ฐ๊ฒฐ ํด ์ฃผ๋ ๊ฒ์ด๋ค. Injector๋ ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์ ์ง ๊ด๋ฆฌํ์ฌ ์ฃผ์ ๊ฐ๋ฅํ ๊ตฌ์ฑ ์์๋ฅผ ์ถ์ ํ๊ณ ํ์ํ ๋ ์ค์ ๋ก ์ฃผ์ ํ๋ ์๋น์ค์ด๋ค. ๋ ์ง์คํธ๋ฆฌ๋ ํ ํฐ์ด๋ผ๊ณ ํ๋ ํค๋ฅผ ํด๋์ค์ ์ฐ๊ด์ํค๋ ๋งต์ด๋ค. ํ ํฐ์ ๋ง์ ์์กด์ฑ ์ฝ์ ํ๋ ์ ์ํฌ์ ๋ฌ๋ฆฌ ๋ฐ๋์ ๋ฌธ์์ด์ ์ ํ์๋ ์๋ค. ์๋ฅผ ๋ค์ด Type ์ฐธ์กฐ์ ๊ฐ์ ์์๊ฐ ๋ ์ ์๊ณ ๊ทธ๊ฒ์ ๋ณดํต ๊ฒฝ์ฐ ์ด๋ค.
์ด ์์์๋ ํ ํฐ๊ณผ ์ฝ์ ํ ํด๋์ค๊ฐ ๊ฐ์ผ๋ฏ๋ก ๊ฐ์ ์์์ ๋ ์งง์ ํ์์ผ๋ก ์ธ ์ ์๋ค.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { PonyRacerAppComponent } from './app.component';
import { RaceService } from './services/race.service';
import { ApiService } from './services/api.service';
@NgModule({
imports: [BrowserModule],
declarations: [PonyRacerAppComponent],
providers: [
RaceService,
ApiService
],
bootstrap: [PonyRacerAppComponent]
})
export class AppModule {
}
ํ ํฐ์ ์ข ์์ฑ์ ๊ณ ์ ํ๊ฒ ์๋ณํด์ผํ๋ค. ์ด ์ฃผ์ฌ๊ธฐ๋ bootstrapModule promise์ ์ํด ๋ฐํ๋๋ฏ๋ก ์ฐ๋ฆฌ๋ ๊ทธ๊ฑธ ๊ฐ์ง๊ณ ๋ ์ ์๋ค.
// in our module
providers: [
ApiService,
{ provide: RaceService, useClass: RaceService },
// let's add another provider to the same class
// with another token
{ provide: 'RaceServiceToken', useClass: RaceService }
]
// let's bootstrap the module
platformBrowserDynamic().bootstrapModule(AppModule)
.then(
// and play with the returned injector
appRef => playWithInjector(appRef.injector)
);
function playWithInjector(inj) {
console.log(inj.get(RaceService));
// logs "RaceService {apiService: ApiService}"
console.log(inj.get('RaceServiceToken'));
// logs "RaceService {apiService: ApiService}" again
console.log(inj.get(RaceService) === inj.get(RaceService));
// logs "true", as the same instance is returned every time for a token
console.log(inj.get(RaceService) === inj.get('RaceServiceToken'));
// logs "false", as the providers are different,
// so there are two distinct instances
}
๋ณด์๋ค์ํผ get ๋ฉ์๋์ ํ ํฐ์ ์ฌ์ฉํ์ฌ ์ธ์ ํฐ์ ์์กด์ฑ์ ์์ฒญํ ์ ์๋ค. ๋ ๊ฐ์ง ๋ค๋ฅธ ํ ํฐ์ ์ฌ์ฉํ์ฌ RaceService๋ฅผ ๋ ๋ฒ ์ ์ธ ํ์ผ๋ฏ๋ก ๋ ๊ฐ์ง ๊ณต๊ธ์๊ฐ ์๋ค. ์ธ์ ํฐ๋ ์ฒ์์ผ๋ก ํน์ ํ ํฐ์ ์์ฒญ ๋ฐ์์ ๋ RaceService์ ์ธ์คํด์ค๋ฅผ ๋ง๋ ๋ค์ ๋งค๋ฒ์ด ํ ํฐ์ ๋ํด ๋์ผํ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค. ๊ฐ ๊ณต๊ธ์๋ง๋ค ๋์ผํ ์์ ์ ์ํํ๋ฏ๋ก ์ฌ๊ธฐ์๋ ์ค์ ๋ก ์ฑ์ ๋ ๊ฐ์ RaceService ์ธ์คํด์ค๊ฐ ์๊ณ ๊ฐ ํ ํฐ์ ํ๋์ฉ ์๋ค.
๊ทธ๋ฌ๋ ํ ํฐ์ ์์ฃผ ์ฌ์ฉํ์ง ์๊ฑฐ๋ ์ ํ ์ฌ์ฉํ์ง ์์ ๊ฒ์ด๋ค. TypeScript์์๋ ํ์์ ์ฌ์ฉํ์ฌ ์์ ์ ์๋ฃํ๋ฏ๋ก ํ ํฐ์ Type ์ฐธ์กฐ์ด๋ฉฐ ๋๊ฐ ํด๋น ํด๋์ค์ ๋ฐ์ธ๋ฉ๋๋ค. ๋ค๋ฅธ ํ ํฐ์ ์ฌ์ฉํ๋ ค๋ฉด @Inject () ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํด์ผํ๋ค. ์์ธํ ๋ด์ฉ์ ์ด ์ฅ์ ๋ง์ง๋ง ๋ถ๋ถ์ ์ฐธ์กฐํ๋ผ.
์ด ์ ์ฒด ์์ ๋ ๋ช ๊ฐ์ง ์ฌํญ์ ์ง์ ํ๊ธฐ์ํ ๊ฒ์ด๋ค. โข ๊ณต๊ธ์๊ฐ ํ ํฐ์ ์๋น์ค์ ์ฐ๊ฒฐํ๋ค. โข ์ธ์ ํฐ๋ ๋์ผํ ํ ํฐ์ ๋ฌป๋ ๋๋ง๋ค ๋์ผํ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค. โข ํด๋์ค ์ด๋ฆ๊ณผ ๋ค๋ฅธ ํ ํฐ ์ด๋ฆ์ ๊ฐ์ง ์ ์๋ค.
๋ฐํ ๋ ์ธ์คํด์ค๊ฐ ์ฒซ ๋ฒ์งธ ํธ์ถ์์ ์์ฑ ๋ ๋ค์ ํญ์ ๋์ผํ๊ฒ ์ ์๋ ค์ง ๋์์ธ ํจํด์ด๊ธฐ๋ ํ๋ค. ์ด ์ธ์คํด์ค๋ฅผ ์ฑ๊ธ ํค์ด๋ผ๊ณ ํ๋ค. ์ด๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ์ฑ ์์๊ฐ์ ์ ๋ณด๋ฅผ ๊ณต์ ํ ์ ์์ผ๋ฏ๋ก ์ค์ ๋ก ์ ์ฉํ๊ณ ๋์ผํ ์๋น์ค ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ฒ ๋๋ค.
์ด์ ๊ฐ์ง RaceService ๋ฌธ์ ๋ก ๋์๊ฐ์ RaceService์ ๋์ผํ ์์ ์ ํ์ง๋ง ํ๋ ์ฝ๋ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ์๋ก์ด ํด๋์ค๋ฅผ ์์ฑํ ์ ์๋ค.
class FakeRaceService {
list() {
return [{ name: 'London' }];
}
}
์ฐ๋ฆฌ๋ ๊ณต๊ธ์ ์ ์ธ์ ์ฌ์ฉํ์ฌ RaceService๋ฅผ FakeRaceService๋ก ๋์ฒด ํ ์ ์๋ค.
// in our module
providers: [
// we provide a fake service
{ provide: RaceService, useClass: FakeRaceService }
]
์ฑ์ ๋ค์ ์์ํ๋ฉด ์ด๋ฒ์ ํ ๋ฒ ๊ฒฝ์ฃผ๊ฐ ์์ ๊ฒ์ด๋ค. ์๋ํ๋ฉด ์ฐ๋ฆฌ ์ฑ์ด ์ฒซ ๋ฒ์งธ ๊ฒฝํ ๋์ ์์กฐ ๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ ์ฑ์ ์๋์ผ๋ก ํ ์คํธ ํ ๋ ๋๋ ์๋ ํ ์คํธ๋ฅผ ์์ฑํ ๋ ๊ณง ๋ณด๊ฒ ๋ ๊ฒ์ด๋ค.
Other types of provider
์ฐ๋ฆฌ์ ์์ ์์๋ ์ฐ๋ฆฌ๊ฐ ์ฑ์ ๊ฐ๋ฐํ ๋ FakeRaceServic๋ฅผ ์ฌ์ฉํ๊ณ ์ค์ RaceServic์ ์ฌ์ฉํ ๋ ์์ฐ ์ค์ ์๋ค. ๋ฌผ๋ก ์๋์ผ๋ก ๋ณ๊ฒฝํ ์๋ ์์ง๋ง ๋ค๋ฅธ ์ ํ์ ๊ณต๊ธ์๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค.: useFactory
// we just have to change this constant when going to prod
const IS_PROD = false;
// in our module
providers: [
// we provide a factory
{
provide: RaceService,
useFactory: () => IS_PROD ? new RaceService(null) : new FakeRaceService()
}
]
์ด ์์ ์์๋ useClass ๋์ ์ useFactory๋ฅผ ์ฌ์ฉํ๋ค. ํฉํ ๋ฆฌ๋ ํ๋์ ์์ ์ผ๋ก ์ธ์คํด์ค๋ฅผ ๋ง๋๋ ํจ์์ด๋ค. ์ด ์์ ๋ ์์๋ฅผ ํ ์คํธํ๊ณ ๊ฐ์ง ์๋น์ค ๋๋ ์ค์ ์๋น์ค๋ฅผ ๋ฐํํ๋ค.
๊ทธ๋ฌ๋ RaceService๋ฅผ ์์ฑํ๊ธฐ ์ํด ์๋ก์ด ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ์ค์ ์๋น์ค๋ก ๋ค์ ์ ํํ๋ฉด ApiService ์ข ์์ฑ์ด ์ธ์คํด์คํ๋์ง ์๋๋ค. ์ด ์์ ๋ฅผ ์๋ ์ํค๋ ค๋ฉด ApiService ์ธ์คํด์ค๋ฅผ ์์ฑ์ ํธ์ถ์ ์ ๋ฌํด์ผ ํ๋ค. ์ข์ ์์ : useFactory๋ deps๋ผ๋ ๋ค๋ฅธ ์์ฑ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค. deps์์๋ ์ข ์ ๋ฐฐ์ด์ ์ง์ ํ ์ ์์ต๋๋ค.
// we just have to change this constant when going to prod
const IS_PROD = true;
// in our module
providers: [
ApiService,
// we provide a factory
{
provide: RaceService,
// the apiService instance will be injected in the factory
// so we can pass it to RaceService
useFactory: apiService => IS_PROD ? new RaceService(apiService) : new
FakeRaceService(),
deps: [ApiService]
}
]
** ๋ช ๊ฐ์ง ์ข ์์ฑ์ด ์๋ ๊ฒฝ์ฐ ๋งค๊ฐ ๋ณ์์ ์์๊ฐ ๋ฐฐ์ด์ ์์์ ๋์ผํด์ผ ํ๋ค. ๋ฌผ๋ก ,์ด ์์ ๋ useFactory์ ๊ทธ ์์กด์ฑ์ ์ฌ์ฉ๋ฒ์ ๋ณด์ฌ์ฃผ๊ธฐ์ํ ๊ฒ์ด๋ค. ๋๋ ์ธ ์ ์๊ณ ,ํด์ผํ๋ค.
// in our module
providers: [
ApiService,
{ provide: RaceService, useClass: IS_PROD ? RaceService : FakeRaceService }
]
IS_PROD์ ๋ํ ์์ ์ ์ธ์ ๋ฒ๊ฑฐ๋ก์ด ์์ ์ด๋ค. ์๋ง๋ ์ฐ๋ฆฌ๋ ์์กด์ฑ ์ฃผ์ ๋ ์ฌ์ฉํ ์ ์์ง ์์๊น? ๋๋ ๋น์ ์ด ๋ณผ ์์๋ ๊ฒ๋ค์ ์กฐ๊ธ ์๊ฒฌ์ ์ฃผ๊ณ ์๋ค :) ๋น์ ์ ๋ฐ๋์ DI์์ ๋ชจ๋ ๊ฒ์ ๊ฐ์ ํ ํ์๋ ์์ง๋ง ์ด๊ฒ์ ๋ค๋ฅธ ๊ณต๊ธ์ ์ ํ์ ๋ณด์ฌ์ฃผ๊ธฐ์ํ ๊ฒ์ด๋ค : useValue
// in our module
providers: [
ApiService,
// we provide a factory
{ provide: 'IS_PROD', useValue: true },
{
provide: RaceService,
useFactory: (IS_PROD, apiService) => IS_PROD ? new RaceService(apiService) : new
FakeRaceService(),
deps: ['IS_PROD', ApiService]
}
]
Hierarchical injectors
Angular 2์์ ๋ง์ง๋ง์ผ๋ก ์์์ผ ํ ์ค์ํ ์ ์ ์ฑ์ ์ฌ๋ฌ ๊ฐ์ ์ธ์ ํฐ๊ฐ ์๋ค๋ ๊ฒ์ด๋ค. ์ค์ ๋ก ๊ตฌ์ฑ ์์๋ง๋ค ํ๋์ ์ธ์ ํฐ๊ฐ ์์ผ๋ฉฐ์ด ์ธ์ ํฐ๋ ํด๋น ์ธ์ ํฐ๋ฅผ ์์๋ฐ๋๋ค. ๋ค์๊ณผ ๊ฐ์ ์ฑ์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด์.
์ฐ๋ฆฌ๋ ์์ ๊ตฌ์ฑ ์์ ์ธ RacesComponent๋ฅผ ๊ฐ์ง ๋ฃจํธ ์ปดํฌ๋ํธ PonyRacerAppComponent๋ฅผ ๊ฐ์ง ๋ชจ๋ AppModule์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ฑ์ ๋ถํธ ์คํธ๋ฉํ๋ฉด ๋ชจ๋์ ๋ฃจํธ ์ธ์ ํฐ๊ฐ ์์ฑ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ์์ฒด ์ธ์ ํฐ๋ฅผ ๋ง๋ค์ด ๋ถ๋ชจ๋ฅผ ์์ํ๋ค.
์ฆ, ๊ตฌ์ฑ ์์์ ์ข ์์ฑ์ ์ ์ธํ๋ฉด Angular 2๋ ํ์ฌ ์ธ์ ํฐ์์ ๊ฒ์์ ์์ํ๋ค. ์์กด์ฑ์ ๋ฐ๊ฒฌํ๋ฉด ์๋ฒฝํ๊ฒ ๋ฐํํ๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, ๋ถ๋ชจ ์ธ์ ํฐ์์ ๋์ผํ ์์ ์ ์ํํ๊ณ ์ข ์์ฑ์ ์ฐพ์ ๋๊น์ง ๋ค์ ์ํํ๋ค. ๊ทธ๊ฒ์ ๊ทธ๋ ์ง ์๋ค. ์์ธ๋ฅผ ๋์ง ๊ฒ์ด๋ค.
์ฆ, ๊ตฌ์ฑ ์์์ ์ข ์์ฑ์ ์ ์ธํ๋ฉด Angular 2๋ ํ์ฌ ์ธ์ ํฐ์์ ๊ฒ์์ ์์ํ๋ค. ์์กด์ฑ์ ๋ฐ๊ฒฌํ๋ฉด ์๋ฒฝํ๊ฒ ๋ฐํํ์ง๋ง ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, ๋ถ๋ชจ ์ธ์ ํฐ์์ ๋์ผํ ์์ ์ ์ํํ๊ณ ์ข ์์ฑ์ ์ฐพ์ ๋๊น์ง ์ํํ๊ณ ์์ธ๋ฅผ ๋์ง ๊ฒ์ด๋ค.
์ด๊ฒ์์ ์ฐ๋ฆฌ๋ ๋ ๊ฐ์ง๋ฅผ ์ถ๋ก ํ ์ ์๋ค : โข ๋ฃจํธ ์ธ์ ํฐ์์ ์ ์ธ ๋ ์ข ์์ฑ์ ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ชจ๋ ๊ตฌ์ฑ ์์์์ ์ฌ์ฉํ ์ ์๋ค. ์๋ฅผ ๋ค์ด ApiService ๋ฐ RaceServicec๋ ์ด๋์์๋ ์ฌ์ฉํ ์ ์๋ค. โข ๋ชจ๋๊ณผ ๋ค๋ฅธ ์์ค์์ ์ข ์์ฑ์ ์ ์ธ ํ ์ ์๋ค. ์ด๋ป๊ฒ ํด์ผํ ๊น?
@Component ๋ฐ์ฝ๋ ์ดํฐ๋ provider ๋ผ๊ณ ํ๋ ๋ ๋ค๋ฅธ ๊ตฌ์ฑ ์ต์ ์ ์ฌ์ฉํ ์ ์๋ค. ์ด provider ์์ฑ์ @NgModule์ providers ์์ฑ์ ๋ํด ์ํ ํ ๊ฒ์ฒ๋ผ ์ข ์์ฑ ๋ชฉ๋ก์ด์๋ ๋ฐฐ์ด์ ์ฌ์ฉํ ์ ์๋ค.
์์ฒด RaceService ๊ณต๊ธ์๋ฅผ ์ ์ธ ํ RacesComponent๋ฅผ ์์ํ ์ ์๋ค.
@Component({
selector: 'ns-races',
providers: [{ provide: RaceService, useClass: FakeRaceService }],
template: `<strong>Races list: {{list()}}</strong>`
})
export class RacesComponent {
constructor(private raceService: RaceService) {
}
list() {
return this.raceService.list();
}
}
์ด ๊ตฌ์ฑ ์์์์ RaceService ํ ํฐ์ ๊ฐ์ง ๊ณต๊ธ์๋ ๋ฃจํธ ์ธ์ ํฐ์ ์ ์ ๋ ๊ฒ๊ณผ ๊ฐ์ FakeRaceService ์ธ์คํด์ค๋ฅผ ํญ์ ์ ๊ณตํ๋ค. ํน์ ๊ตฌ์ฑ ์์์ ๋ํด ๋ค๋ฅธ ์๋น์ค ์ธ์คํด์ค๋ฅผ ์ํ๊ฑฐ๋ ํ์ํ ๋ชจ๋ ๊ฒ์ ์ ์ธํ๋ ์๋ฒฝํ๊ฒ ์บก์ํ ๋ ๊ตฌ์ฑ ์์๋ฅผ ์ํ ๊ฒฝ์ฐ์ ๋งค์ฐ ์ ์ฉํ๋ค.
๊ฒฝ๊ณ !! ์ฑ์ ๋ชจ๋๊ณผ ๊ตฌ์ฑ ์์์ ๊ณต๊ธ์ ์์ฑ์ ์ข ์์ฑ์ ์ ์ธํ๋ฉด ์ด ์ข ์์ฑ์ ๋ ์ธ์คํด์ค๊ฐ ์์ฑ๋์ด ์ฌ์ฉ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ํ ๊ตฌ์ฑ ์์ ๋ง ์๋น์ค์ ์ ๊ทผ ํด์ผํ๋ ๊ฒฝ์ฐ provider ์์ฑ์ ์ฌ์ฉํ์ฌ ๊ตฌ์ฑ ์์์ ์ธ์ ํฐ ์์ ์ด ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค. ์ฑ ์ ์ฒด์์ ์ข ์์ฑ์ ์ฌ์ฉํ ์ ์์ผ๋ฉด ๋ฃจํธ ๋ชจ๋์ ์ ์ธํ์ฌ๋ผ.
DI without types
ํ ํฐ์ ์ฌ์ฉํ๊ณ TypeScript ์ ํ์ ์์กดํ์ง ์์ผ๋ ค๋ ๊ฒฝ์ฐ ์ฝ์ ํ ์ข ์์ฑ๋ง๋ค ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ @Inject ()์ด๋ฉฐ ์ฝ์ ํ ์ข ์์ฑ์ ํ ํฐ์ ๋ฐ๋๋ค. ๋ค์๊ณผ ๊ฐ์ด ApiService ์๋น์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ๋์ผํ RaceService๋ฅผ ์์ฑํ ์ ์๋ค.
import { Injectable, Inject } from '@angular/core';
import { ApiService } from './api.service';
@Injectable()
export class RaceService {
constructor(@Inject(ApiService) apiService) {
this.apiService = apiService;
}
list() {
return this.apiService.get('/races');
}
}
TypeScript ์์ด ์์ ์์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์๋ ์ํค๋ ค๋ฉด babel์ decorator์ ํจ๊ป ์ฌ์ฉํด์ผํ๊ณ angle2-annotations ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํด์ผ ํ๋ค.
Reference URL
Last updated
Was this helpful?