惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
T
The Blog of Author Tim Ferriss
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Engineering at Meta
Engineering at Meta
量子位
I
InfoQ
Jina AI
Jina AI
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
Google Developers Blog
J
Java Code Geeks
Recent Announcements
Recent Announcements
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
V
V2EX
腾讯CDC
P
Proofpoint News Feed
A
About on SuperTechFans
爱范儿
爱范儿
U
Unit 42
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI

mafeifan 的编程技术分享

mafengwo-mp3-downloader | mafeifan 的编程技术分享 示例页面 | mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 查看 default namespace 下的 default service account名称 mafeifan 的编程技术分享 检查日志 | mafeifan 的编程技术分享 bridge fdb show dev flannel.1 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享 mafeifan 的编程技术分享
mafeifan 的编程技术分享
2026-01-16 · via mafeifan 的编程技术分享

首先介绍 Angular 中依赖注入的相关概念:

Service 服务 ​

Service 的表现形式是一个class,可以用来在组件中复用 比如 Http 请求获取数据,日志处理,验证用户输入等都写成Service,供组件使用。

typescript

import { Injectable } from '@angular/core';
// 在 Angular 中,要把一个类定义为服务,就要用`@Injectable` 装饰器来提供元数据

@Injectable({
  // we declare that this service should be created
  // by the root application injector.
  providedIn: 'root',
})
export class LoggerService {
  warn(msg) { 
    return console.warn(msg); 
  }
}

Injector 注入器 ​

一般不用自己手动注入,Angular 会在启动过程中为你创建全应用级注入器以及所需的其它注入器。

Provider 提供商 ​

是一个对象,告诉 Injector 应该如何获取或创建依赖。

打开Angular看下面的代码片段 app.module.ts

typescript

@NgModule({
  declarations: [
    ....
  ],
  imports: [
    ....
  ],
  // providers 告诉 Angular 应用哪些对象需要依赖注入
  // providers 是个数组,每一项都是provider
  providers: [
    //  简写,等价 {provider: LoggerService, useClass: LoggerService}
    LoggerService,
    { 
       provide: RequestCache, 
       useClass: RequestCacheWithLocalStorage 
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: UrlInterceptor,
      multi: true
    },
  ],
  bootstrap: [AppComponent]
})

DI token(令牌) ​

provide 属性提供了provider 的token,也叫令牌,表示在构造函数中指定的类型。 也就是说,当constructor(private productService: ProductService){...} 指定了ProductService,就会去找token是productService的provider。

image.png

Provider 的几种写法 ​
  1. useClass providers: [{provide: ProductService, useClass: ProductService} ] 的简写是 providers: [ ProductService ] useClass属性指定实例化方式,表示是 new 一个 ProductService,如果userClass" AnotherProductService 真正实例化的就是 AnotherProductService。
  2. userFactory 除了useClass写法,还可以使用 userFactory 工厂方法,这个方法返回的实例作为构造函数中productService参数的内容。 providers: [{provide: ProductService, userFactory: () => {}} ] 这样可以根据条件具体实例化某对象,更加灵活

typescript

providers: [{
  provide: ProductService, 
  userFactory: () => {
    let logger = new LoggerService();
    let dev = Math.random() > 0.5;
    if (dev) {
      return new ProductService(logger);
    } else {
      return new AnotherProductService(logger);
   }
  }
}, LoggerService ]

上面的写法有个弊端LoggerService和ProductService耦合太强 进一步优化,利用deps参数,指工厂声明所依赖的参数。

typescript

providers: [{
    provide: ProductService, 
    userFactory: (logger: LoggerService) => {
      let dev = Math.random() > 0.5;
      if (dev) {
        return new ProductService(logger);
      } else {
        return new AnotherProductService(logger);
     }
    },
    deps: [ LoggerService ]
  }, 
  LoggerService
]

再次优化,定义第三个提供器,token是IS_DEV_ENV,值是具体的false

typescript

providers: [{
    provide: ProductService, 
    // 注入的 顺序和deps对应
    userFactory: (logger: LoggerService, isDev) => {
      if (isDev) {
        return new ProductService(logger);
      } else {
        return new AnotherProductService(logger);
     }
    },
    deps: [ LoggerService, 'IS_DEV_ENV' ]
  }, 
  LoggerService,
  {provide: 'IS_DEV_ENV', useValue: false}
]

一般来说可以创建一个类型为对象的提供器供注入

typescript

providers: [{
    provide: ProductService, 
    // 注入的 顺序和deps对应
    userFactory: (logger: LoggerService, appConfig) => {
      if (appConfig.isDev) {
        return new ProductService(logger);
      } else {
        return new AnotherProductService(logger);
     }
    },
    deps: [ LoggerService, 'APP_CONFIG' ]
  }, 
  LoggerService,
  { provide: 'APP_CONFIG', useValue: {isDev: false }}
]

提供器的作用域 ​

image.png

provide声明在App模块中,则对所有模块可见

provide声明在某组件中,只对该组件及其子组件可见。其他组件不可以注入。 当声明在组件和模块中的提供器具有相同的token时,声明在组件中的提供器会覆盖模块中的那个提供器。

@Injectable 装饰器 ​

表示FooService可以通过构造函数注入其他服务 举个例子,如果注释掉

typescript

// @Injectable({
//   providedIn: 'root'
// })

就会报错

image.png

image.png

为什么在组件中没有写@Injectable也能直接注入service? 我们知道定义组件要写@Component装饰器,定义管道要写@Pipe装饰器,他们都是Injectable的子类。 同时Component又是Directive的子类,所以所有的组件都是指令。

手动注入 ​

typescript

import { Component, OnInit, Injector } from '@angular/core';
import { LoggerService } from '../_service/logger.service';

@Component({
  selector: 'app-di',
  templateUrl: './di.component.html',
  styleUrls: ['./di.component.styl']
})
export class DIComponent implements OnInit {
  logger: LoggerService;
  // 手动注入
  constructor(
    private injector: Injector
  ) {
    this.logger = injector.get(LoggerService);
  }

  ngOnInit() {
    this.logger.log()
  }
}