There are two ways to make a service a singleton in Angular:
- Set the providedIn property of the @Injectable() to “root”.
- Include the service in the AppModule or in a module that is only imported by the AppModule
以上是Angular 官网上的原话,说是有两种方法在Angular 应用中提供单例服务,一个是对于可注入的服务配置providedIn: 'root' , 二个是只在AppModule 里面引入服务或者只在AppModule 里面引入提供服务的模块。
所以使用示例中完整代码, 发现了不能理解的问题,问题总结下来就是就算配置providedIn: 'root‘ , 貌似服务也不是单例的,不管是急性还是惰性加载模块,还需要看看是否在component 里面再次定义了providers。如有问题,欢迎大家指正讨论!
具体执行过程如下: app.module.ts 代码如下:
@NgModule({
imports: [
BrowserModule,
ContactModule,
DevicesModule,
GreetingModule,
AppRoutingModule
],
declarations: [
AppComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts 代码如下:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-greeting></app-greeting>
<nav>
<a routerLink="devices" routerLinkActive="active">Devices</a>
<a routerLink="contact" routerLinkActive="active">Contact</a>
<a routerLink="items" routerLinkActive="active">Items</a>
<a routerLink="customers" routerLinkActive="active">Customers</a>
</nav>
<router-outlet></router-outlet>
`
})
export class AppComponent {
}
其中Device 和Contact 是急性加载模块,Items 和Customers 是惰性加载模块。 导航下方的形如times 2’s 为注入的UserService.username
user.service.ts 中配置了providedIn: 'root' , 需要注意这个是一个重要的配置,这个告知Angular在应用层面提供服务。
import { Injectable, Optional } from '@angular/core';
let nextId = 1;
export class UserServiceConfig {
userName = 'Philip Marlowe';
}
@Injectable({providedIn: 'root'})
export class UserService {
id = nextId++;
constructor(@Optional() config?: UserServiceConfig) {
console.log('user service constructor', config, this.id,);
if (config) { this._userName = config.userName; }
}
get userName() {
const suffix = this.id > 1 ? ` times ${this.id}` : '';
return this._userName + suffix;
}
private _userName = 'Sherlock Holmes';
}
分别点击Device 和Items, 渲染出来的都是包含Sherlock Holmes times 3's Devices ,说明点击Device 的时候重新生成了一个新的UserService实例,并且Items 和 Device 使用的是同一个UserService实例。Device 和Items 相同的配置都是在构造函数中直接引用UserService, 形如:
import { Component } from '@angular/core';
import { UserService } from '../greeting/user.service';
@Component({
selector: 'app-devices',
template: `<h2>{{userName}}'s Devices</h2>`,
})
export class DevicesComponent {
userName = '';
constructor(private userService: UserService) {
this.userName = userService.userName;
}
}
分别点击Contact 和 Customer, 渲染出来的都是Sherlock Holmes times N's , 其中N 是不断上涨的,说明不管点击Contact 还是Customer 都会重新生成新的UserService 实例,而且这俩模块的UserService实例是相互隔离的。Contact和Customer 模块相同的配置都是在@Component 装饰器中配置了Providers: [UserService] 。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Contact, ContactService } from './contact.service';
import { UserService } from '../greeting/user.service';
@Component({
selector: 'app-contact',
template: `<h2>{{userName}}'s Contacts</h2>`,
styleUrls: [ './contact.component.css' ],
providers: [UserService]
})
export class ContactComponent implements OnInit {
userName = '';
constructor(private contactService: ContactService, userService: UserService) {
this.userName = userService.userName;
}
}
|