You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular能否创建非单例Service?如何实现?

Angular模块间服务独立实例实现方案

完全可行,以下是针对你的需求的具体实现方法:

为什么之前的配置无效

Angular中,预加载(eagerly loaded)模块的@NgModule.providers会被合并到根注入器,因此所有预加载模块共享同一服务实例;只有懒加载模块会创建独立的模块注入器,此时声明在providers中的服务才会生成独立实例。如果你的报表模块是预加载的,自然会出现数据共享的问题。

方案1:使用懒加载模块(适合允许懒加载的场景)

将每个报表模块配置为懒加载,通过路由的loadChildren加载模块,此时每个懒加载模块会拥有独立的注入器,在模块的providers中声明ReportParamsStoreService即可获得独立实例:

  1. 配置路由:
const routes: Routes = [
  { path: 'inss-report', loadChildren: () => import('./inss-report/inss-report.module').then(m => m.InssReportModule) },
  { path: 'irrf-report', loadChildren: () => import('./irrf-report/irrf-report.module').then(m => m.IrrfReportModule) },
  { path: 'fgts-report', loadChildren: () => import('./fgts-report/fgts-report.module').then(m => m.FgtsReportModule) }
];
  1. 在每个报表模块的@NgModule中声明服务:
@NgModule({
  declarations: [InssReportComponent],
  providers: [ReportParamsStoreService] // 懒加载模块会创建独立实例
})
export class InssReportModule { }

方案2:使用providedIn: 'any'(推荐,支持预加载/懒加载模块)

Angular 6+ 提供了providedIn: 'any'选项,该配置会让服务在每个注入器中生成独立实例,无论模块是预加载还是懒加载,无需在模块providers中重复声明:

  1. 修改服务的装饰器:
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'any' // 关键配置:每个注入器对应一个实例
})
export class ReportParamsStoreService {
  private reportParams: Record<string, any> = {};

  setParam(key: string, value: any): void {
    this.reportParams[key] = value;
  }

  getParam(key: string): any {
    return this.reportParams[key];
  }
}
  1. 在报表模块的组件中直接注入服务即可,每个模块会自动获得独立实例:
import { Component } from '@angular/core';
import { ReportParamsStoreService } from '../report-params-store.service';

@Component({
  selector: 'app-inss-report',
  template: `<button (click)="setParams()">设置INSS参数</button>`
})
export class InssReportComponent {
  constructor(private paramsStore: ReportParamsStoreService) { }

  setParams(): void {
    this.paramsStore.setParam('reportType', 'INSS');
    // 该参数仅存在于INSS模块的服务实例中
  }
}

方案3:共享模块forChild模式(适合服务需随共享模块分发的场景)

如果你的服务需要和其他共享组件/指令一起封装在共享模块中,可以通过forChild方法为每个导入模块提供独立实例:

  1. 创建共享模块:
import { NgModule, ModuleWithProviders } from '@angular/core';
import { ReportParamsStoreService } from './report-params-store.service';

@NgModule({
  // 声明共享组件/指令等
})
export class ReportSharedModule {
  // 静态方法为每个导入模块提供独立服务实例
  static forChild(): ModuleWithProviders<ReportSharedModule> {
    return {
      ngModule: ReportSharedModule,
      providers: [ReportParamsStoreService]
    };
  }
}
  1. 每个报表模块导入ReportSharedModule.forChild():
@NgModule({
  declarations: [IrrfReportComponent],
  imports: [ReportSharedModule.forChild()]
})
export class IrrfReportModule { }

以上三种方案都能实现各报表模块服务实例的隔离,无需重复编写服务代码。

内容的提问来源于stack exchange,提问作者Fabio Mendonça

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:35:00