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

推荐订阅源

D
DataBreaches.Net
IT之家
IT之家
博客园_首页
博客园 - 【当耐特】
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
G
Google Developers Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Announcements
Recent Announcements
F
Fortinet All Blogs
GbyAI
GbyAI
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
I
InfoQ
H
Help Net Security
T
Tailwind CSS Blog
B
Blog RSS Feed
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
博客园 - 叶小钗
雷峰网
雷峰网
量子位

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()
  }
}