初學Angular
,可能對一堆註解有些懵。typescript
咱們一塊兒經過實例來探討Angular
的依賴注入。bootstrap
一個命令建的StockService
,一個手動建的TestService
。數組
@Injectable({ providedIn: 'root' }) export class StockService { constructor(private testService: TestService) { } }
export class TestService { constructor() { } }
TestService
未加@Injectable
註解,只是一個普通的TypeScript
類。promise
當前臺組件中用到StockService
時,Angular
爲咱們構造StockService
,構造函數中依賴TestService
,而後Angular
去構造TestService
。app
Uncaught (in promise): Error: StaticInjectorError(AppModule)[TestService]: StaticInjectorError(Platform: core)[TestService]: NullInjectorError: No provider for TestService!
而後發現控制檯報錯,沒法提供TestService
,由於它沒有被Angular
管理。dom
import {Injectable} from '@angular/core'; @Injectable() export class TestService { constructor() { } }
加上@Injectable
,將該類交給Augular
管理。ide
無效,仍然報錯。發現只交給Angular
託管是不行的,咱們還須要聲明提供器。函數
須要提供器告訴Angular
如何注入相關對象。學習
@NgModule({ declarations: [], imports: [], providers: [TestService], bootstrap: [AppComponent] }) export class AppModule { }
在AppModule
的providers
數組中聲明TestService
提供器。優化
按類型提供,因此上面的聲明與下面的代碼是等價的。
providers: [{ provide: TestService, useClass: TestService }]
標記在AppModule
上,表示該TestService
的注入是應用在該模塊上的。在該模塊中,TestService
是單例的。
{ provide: TestService, useClass: TestService }
,表示當須要注入TestService
類型的對象時,使用TestService
類構造出的對象進行注入。
Angular
中,爲何@Component
、@Pipe
裏能用構造函數注入@Injectable
呢?答案與Spring
一致,爲何@Controller
、@Service
裏能Autowired
呢?思想相同。
@NgModule({ providers: [TestService] }) export class AppModule { } @Component({ providers: [{ provide: TestService, useClass: AnotherTestService }] }) export class StockComponent { constructor(private testService: TestService) { } }
聲明一個模塊級的與一個組件級的提供器,表示在本模塊或本組件中應該注入什麼。
就像如上代碼,聲明在整個AppModule
模塊中,注入的TestService
是TestService
類實例化的。
可是具體到組件,StockComponent
,雖然聲明整個模塊都使用TestService
,可是有時不符合需求,因此在此組件中使用AnotherTestService
注入。
就像Spring
中的@Primary
與@Qualifier
同樣。
經過useValue
的值提供,能夠定義一些常量,又是枚舉的思想,咱們使用引用,而不是用常量。
{ provide: domain, useValue: 'www.mengyunzhi.com' }
除了值提供還有工廠方法,當Angular
默認的實例化對象沒法知足咱們的要求時,咱們要寫本身的工廠函數生成咱們的對象實例。
可是注意:雖然該方法叫工廠方法,可是該方法只在第一次用到該對象時執行一次,之後再須要用的仍是以前構造出來的對象。
雖然叫工廠方法,可是仍是單例的。
{ provide: ProductService, useFactory: () => { 返回一個對象實例 } }
如今若是用ng
生成的Angular
服務,標準的寫法是providedIn: 'root'
。
粗略學習了一下,搖樹優化就是按需加載,減少咱們的包體積,縮短應用的加載時間。
@Injectable({ providedIn: 'root' })
只要在服務自己的@Injectable()
裝飾器中指定,而不是在依賴該服務的NgModule
或組件的元數據中指定,你就能夠製做一個可搖樹優化的提供商。
要想覆蓋可搖樹優化的提供商,請使用其它提供商來配置指定的NgModule
或組件的注入器,只要使用@NgModule()
或@Component()
裝飾器中的providers: []
數組就能夠了。
經過上面的學習,咱們知道了Angular
中的依賴注入是經過構造函數的參數注入來實現的。
可是隻要是經過構造函數實現的IOC
容器就會有問題,就像Spring
中同樣,若是循環依賴了怎麼解決呢?
@Injectable({ providedIn: 'root' }) export class StockService { constructor(private testService: TestService) { } }
@Injectable({ providedIn: 'root' }) export class TestService { constructor(private stockService: StockService) { } }
Circular dependency detected: src/app/service/stock.service.ts -> src/app/service/test.service.ts -> src/app/service/stock.service.ts Circular dependency detected: src/app/service/test.service.ts -> src/app/service/stock.service.ts -> src/app/service/test.service.ts
與Spring
同樣,若是循環了,由於是使用構造函數注入,因此一個對象都構造不出來,沒法解決。開發時應避免循環依賴。
萬物相通。
Hello, Angular!