Angular拦截器场景下单例LoginService被创建两次如何解决
问题原因
你配置的两套注入规则触发了LoginService的两次实例化:
- 第一次实例化:当业务代码注入
AbstractLoginService时,Angular匹配AppModule中配置的{ provide: AbstractLoginService, useClass: LoginService }规则,创建第一个LoginService实例。 - 第二次实例化:拦截器中直接注入具体类
LoginService,而LoginService自身配置了providedIn: 'root',Angular会从根注入器创建第二个独立的LoginService实例返回给拦截器。
修复方案
两步修改即可保证LoginService全局单例:
- 统一使用抽象类作为注入令牌,修改拦截器的注入类型,将具体类
LoginService替换为抽象类AbstractLoginService
修改后的HTTPDemo.interceptor.ts代码:
@Injectable({ providedIn: 'root' }) export class HTTPDemoInterceptor implements HttpInterceptor { constructor( // 这里换成抽象类作为注入类型 private loginService: AbstractLoginService, ) { console.log('CONSTRUCTOR HTTPDemoInterceptor'); } // 其余拦截逻辑不变 }
- 移除LoginService的全局自动提供配置,避免后续误注入具体类时重复生成实例,修改
login.service.ts的装饰器:
// 去掉providedIn: 'root',仅保留空@Injectable @Injectable() export class LoginService implements AbstractLoginService { private timestamp = 0 constructor() { this.timestamp = +new Date(); console.trace('CONSTRUCTOR LoginService', this.timestamp); } // 其余业务逻辑不变 }
额外提示:原LoginService的构造函数中重复声明了timestamp属性,属于语法问题,建议删除构造函数的timestamp参数,直接给类属性赋值即可
修改完成后所有依赖AbstractLoginService的场景都会拿到同一个LoginService实例,不会再重复构造。
内容的提问来源于stack exchange,提问作者Kamil Kiełczewski
相关产品推荐
相关产品推荐

