在其他多个延迟加载模块之间共享延迟加载(不在 App.module 中)服务(DI 上下文)?

Share lazy-loaded (not in App.module) service (DI context) between other multiple lazy loaded modules?

假设场景:

App.module
   |__Lazy1.module
   |    \__LazyService1.module
   |__Lazy2.module
   |    \__LazyService1.module
   \__(many more)

目标是让 LazyService1.moduleLazy1/2.module 提供单例实例,但仅在获取 Lazy1/Lazy2 时才需要加载。

Angular 仅创建和解析根 DI 上下文一次。任何后续上下文(对于惰性模块)都是子上下文。我的问题是我不想在 App.module 中提供服务 (LazyService1.module)(这是一个大模块,只有 2 个懒加载的模块使用),所以逻辑上我的 LazyService1.module 会不能在根 DI 上下文中解析。

我需要以某种方式在 2 个延迟加载模块之间共享 DI 上下文,而不必使其成为根依赖项(在 App.module 中)。

有没有办法定义共享DI?一个模块可以访问另一个模块的 DI 上下文吗?

是否可以在root中提供懒加载服务供其他懒加载模块使用,而不是从root提供App.module?

至于堆栈 - 我不认为我可以提供堆栈,因为我不知道它的外观。我可以实现 eagerly 在 root 中提供服务,但这不是这里的问题。

编辑 2:

App.module:

@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [
        // Used by all:
        BrowserModule,
        BrowserAnimationsModule,
        CommonModule,
        HttpClientModule,
        // App router:
        AppRoutingModule
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

延迟加载路由模块:

const routes: Routes = [
    { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) },
    { path: 'main', loadChildren: () => import('./main/main.module').then(m => m.MainModule) },
    ... many others, lazy or not
];

服务模块:

@NgModule({
    providers: [
        AuthenticationService
    ],
    declarations: [...],
    exports: [...],
    imports: [
        CommonModule,
    ]
})
export class SecurityModule { }

服务:

@Injectable()
export class AuthenticationService { ... }

然后我们有 2 个懒惰的:adminmain

如果我像这样导入 SecurityModule

@NgModule({
    imports: [
        SecurityModule
    ]
})
export class MainModule { }

我最终会为 Main 和 Admin 使用单独的 AuthenticationService。 如果我在 App.module 中导入它,当然它可以工作,但是我必须加载巨大的 SecurityModule,当它只在 Main/Admin 中需要时可能永远不会被访问。

你不能在模块之间共享服务,那会破坏制作模块的全部目的。 但是对于场景你可以试试这个方法

App.module
   |__Lazy1.module  
   |                (import)<= SharedModule -> LazyService1.module
   |__Lazy2.module  
   |
   \__(many more)

上面解释了创建一个新模块作为共享模块并创建您想要在服务之间共享的服务,并将该模块导入到您需要该服务的其他模块。

更新:

您需要创建一个名为 forRoot 的静态方法来导出服务以及模块本身。这将为您提供共享模块的所有导入的单个实例。

看看这个 link,我 100% 确定它能回答您的问题。编码愉快:)

Shared Dependency Tree

希望对您有所帮助,如有任何疑问,请告诉我

到目前为止,所有答案都读起来很不错(即使在发布问题之前我实际上已经阅读了大量答案)。

forRoot 的问题(我认为所有建议的链接)是(对我而言)它不是真正的 DI,因为它强烈耦合 App.module 和注入的 module/service -这就是我在问题中描述的整个问题。

因为我是一个坚强的 Java 编码员(而且我们确实喜欢我们的依赖注入)我不能动摇必须有一种方法让它成为真正的 DI 的想法。

所以我很确定 Shashank Vivek 在这里至少有部分错误:

because it is the only way to make it work in Angular

之所以很难找到一个好的解决方案是因为 Angular 是该死的快速开发框架,你发现的几乎 90% 的内容都在版本 2-4 左右。

无论如何 - 自 Angular 6 以来,我们在装饰器中有 providedIn,虽然我已经知道几个月了(因为据说 "true DI" 比较forRoot),这让我感到惊讶:它实际上是可摇树的

所以总而言之 - 你可以从字面上获取服务,用 providedIn 标记它,而不是在你实际使用它的地方之外的任何地方(实际上没有声明或导入)。

事实证明,服务是它们自己的产物,Angular 足够聪明,可以将它们与任何使用它们的东西一起加载和打包。

所以我的问题的答案是:

  1. 删除对惰性服务的所有引用。
  2. @Injectable({ providedIn: 'root' })
  3. 标记它们
  4. 只需将它们注入到您需要的构造函数中(在延迟加载的模块中)。

Angular 将使包含服务(和其他内容)的部分惰性模块在许多惰性模块(如我的示例中)之间共享,并在加载时加载它们。该实例将在 root 中提供(在我的例子中)并在所有应用程序(惰性模块)之间共享。

为了更进一步(因为 DI 就是爱),这里有一本关于如何进一步发展的好书(我说的是 Spring 级别的更进一步)。 :)

https://angular.io/guide/dependency-injection-providers#tree-shakable-providers

https://www.softwarearchitekt.at/aktuelles/the-new-treeshakable-providers-api-in-angular/

我很惊讶这很难找到 :O ...深埋在 angular 文档中。

Here is a demo code to play around with it !