Angular 4中如何将CoreModule单例注入多模块以共享MyService
Hey there! Let's walk through how to make your CoreModule a proper singleton and ensure MyService is shared consistently across your app—even when dynamically loading components like Component B into Component A.
Your existing code already has key safeguards in place, but let's refine the setup to work seamlessly across all modules and dynamic component scenarios:
1. Confirm Your Singleton Protection Logic
The check in your CoreModule constructor is perfect for preventing accidental duplicate imports—it throws an error if the module is loaded more than once:
export class MyService { constructor() { } // Your service logic here... } export class CoreModule { constructor(@Optional() @SkipSelf() core: CoreModule) { if (core) { throw new Error('Only one instance of CoreModule should exist!') } } static forRoot(): ModuleWithProviders<CoreModule> { return { ngModule: CoreModule, providers: [MyService] }; } }
This ensures no module can accidentally create a second instance of CoreModule (and thus a second MyService).
2. Correct Import Patterns
Root Module (AppModule)
Only the root module should call forRoot()—this registers MyService as an application-wide singleton:
@NgModule({ imports: [ CoreModule.forRoot(), // Other app-wide modules... ] }) export class AppModule { }
Feature/Lazy-Loaded Modules
All other modules should import CoreModule without calling forRoot(). This gives them access to any declarations in CoreModule while reusing the singleton MyService registered by the root module:
@NgModule({ imports: [ CoreModule, // Other feature modules... ] }) export class FeatureModule { }
3. Handling Dynamic Component Loading
When dynamically loading Component B into Component A, you don’t need extra setup for MyService—Angular’s injector system will handle it:
- If Component B lives in a lazy-loaded module that imports
CoreModule, it will automatically use the root singletonMyService(injectors bubble up to the root by default). - If you’re creating Component B directly via
ComponentFactoryResolver, the component will inherit the injector from Component A— which already has access to the singletonMyService:
@Component({...}) export class ComponentA { constructor( private resolver: ComponentFactoryResolver, private viewContainerRef: ViewContainerRef, private myService: MyService // Already the singleton instance ) {} loadComponentB() { const factory = this.resolver.resolveComponentFactory(ComponentB); const componentRef = this.viewContainerRef.createComponent(factory); // Component B can inject MyService directly and get the same singleton } }
4. Verify the Singleton Works
To double-check you’re getting a single instance of MyService, add a unique identifier to the service and log it:
export class MyService { private instanceId = Math.random().toString(36).slice(2); constructor() { console.log(`MyService instance created: ${this.instanceId}`); } getInstanceId() { return this.instanceId; } }
Inject MyService into Component A and Component B, then call getInstanceId()—you’ll see the same ID logged for both, confirming the singleton is working.
内容的提问来源于stack exchange,提问作者user3656360

