Angular 配置依赖提供者

219 阅读3分钟

正常情况在module或者component中注入服务的写法: providers: [LoggerService],

但是,可以将 DI 配置为使用不同的类或任何其他不同的值来与 LoggerService 类关联。因此,当注入 LoggerService 时,会改为使用这个新值。

类提供者语法是一个简写表达式,可以扩展为由 Provider 接口定义的提供者配置信息。

在这种情况下,Angular 将 providers 值展开为完整的提供者对象,如下所示:

[{ provide: LoggerService, useClass: LoggerService }]

展开后的提供者配置是一个具有两个属性的对象字面量:

  • provide 属性包含一个令牌,该令牌会作为定位依赖值和配置注入器时的键。

  • 第二个属性是一个提供者定义对象,它会告诉注入器如何创建依赖值。提供者定义对象中的键可以是以下值之一:

    • useClass - 此选项告诉 Angular DI 在注入依赖项时要实例化这里提供的类
    • useExisting - 允许你为令牌起一个别名,并引用任意一个现有令牌。
    • useFactory - 允许你定义一个用来构造依赖项的函数。
    • useValue - 提供了一个应该作为依赖项使用的静态值。

下面就针对 useClass useExisting useFactory useValue 这四个key做一下解释。

useClass

写法:

[{ provide: Logger, useClass: EvenBetterLogger }]

写法解读:

当在组件或任何其他类中请求 Logger 依赖项时,将转而实例化 EvenBetterLogger 类。

@Injectable({
  providedIn: 'root'
})
export class Logger {
  logs: string[] = []; // capture logs for testing

  log(message: string) {
    this.logs.push(message);
    console.log('Logger==', message);
  }

}
@Injectable({
  providedIn: 'root'
})
export class EvenBetterLogger extends Logger {
  constructor(private userService: UserService) { super(); }
  override log(message: string) {
    const name = this.userService.user.name;
    super.log(`Message to ${name}: ${message}`);
  }
}

也就是调用服务 Logger 的 log方法时,控制台会输出 Message to ****。

别名提供者:useExisting

useExisting 提供者键允许你将一个令牌映射到另一个。实际上,第一个令牌是与第二个令牌关联的服务的别名,创建了两种访问同一个服务对象的方式。

OldLoggerService

@Injectable({
  providedIn: 'root'
})
export class OldLoggerService {
  text = '';
  constructor() { }
  log() {
    console.log("this old logger", this.text);
  }

}

NewLoggerService

@Injectable({
  providedIn: 'root',

})
export class NewLoggerService {
  text = '';
  constructor() { }
  log() {
    console.log("this new logger", this.text);
  }
}

Component中使用方法:

providers:[
    {provide:OldLoggerService, useExisting:NewLoggerService}
  ]

使用这两个服务:

  constructor(private oldLogger:OldLoggerService, private newLogger:NewLoggerService) {
    this.newLogger.text = "newText";
    this.oldLogger.log();
  }

这时控制台输出 ‘this new logger"newText"’

useExistingusrClass对比:

  • useExisting:两个服务之间不需要是继承关系。但是需要有相同的属性和方法。
  • usrClass:需要是继承关系

useFactory

useFactory 提供者键允许你通过调用工厂函数来创建依赖对象。使用这种方法,你可以根据 DI 和应用程序中其他地方的可用信息创建动态值。

比如创建的服务需要依赖一个boolean值,

这时候就需要在使用useFactory调用工厂函数来创建对象提供这个boolean值

@Injectable({
  providedIn: 'root',
  //如果服务中需要一些额外参数,例如boolean值,需要使用这种方式提供.
  useFactory: (logger: Logger, userService: UserService) =>
    new HeroService(logger, userService.user.isAuthorized),
  //在服务中使用其他服务,需要这样添加依赖
  deps: [Logger, UserService],
})
export class HeroService {

  getListDatas() {
    return ['张三', '李四'];
  }
  //初始化
  constructor(
    private logger: Logger,
    private isAuthorized: boolean) { }
  
}

useValue

useValue 键允许你将固定值与某个 DI 令牌相关联。

根据代码理解,就是为组件初始化对象(令牌),提供默认参数:

interface AppConfig{
  content:string
}
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  viewProviders:[],
  providers:[
  
    { provide: APP_CONFIG, useValue: { content: "全局的配置信息" } }
  ]
})
export class AppComponent {

  constructor(@Inject(APP_CONFIG) private appConfig:AppConfig) {
    console.log("this.appConfig.content==", this.appConfig.content);
  }

  ngOnInit() {
    
    
  }


}