欢迎各位兄弟 发布技术文章
这里的技术是共享的
在高级语言或者脚本语言中,我们要实例化一个object,一般我们用 new object(),或者java的DI,那么在NG里面一样,我们要使用一个服务,那么就会通过providers来创建或者获取服务的实例,providers现在有多种类型可以选择,
TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[];
ClassProvider :
export interface ClassProvider extends ClassSansProvider {
/**
* An injection token. (Typically an instance of `Type` or `InjectionToken`, but can be `any`).
*/
provide: any;
/**
* If true, then injector returns an array of instances. This is useful to allow multiple
* providers spread across many files to provide configuration information to a common token.
* 参考拦截器实现
*/
multi?: boolean;
/**
* Class to instantiate for the `token`.
* 设置注入的对象
*/
useClass: Type<any>;
}
eg:
@NgModule({
imports: [
CommonModule,
],
providers: [
UtilService, //方式一
{provide: UtilService, useClass: UtilService},//方式二
]
})
其中provide属性作为Injection Token使用,用于定位依赖,用于注册 userClass这个提供商,这个其实就是在后面的程序中使用的服务的名字,他的类型可以是一个BaseClass,也可以是一个InjectionToken
useClass
表示我们使用哪一个服务类去创建实例,当然我们可以使用不同的服务类,只要这些服务的类满足我们相应的需求就行,
方式一和方式二一样的功能,在ng官方的例子中列举了一个很详细的例子,参考官方【多级依赖注入】,当描述不同的车辆,宾利和比亚迪虽然都是小车车,但是在大众认知中肯定是两个不同的东西,那么要在代码逻辑如何描述他,看官宣代码:
////////// BCarComponent ////////////
@Component({
selector: 'b-car',
template: `
<div>假如我是BYD,我也车:B: {{description}}</div>
<c-car></c-car>
`,
providers: [
{ provide: CarService, useClass: CarService2 },
{ provide: EngineService, useClass: EngineService2 }
]
})
////////// CCarComponent ////////////
@Component({
selector: 'c-car',
template: `
<div>假如我是Bentley,我也车:B: {{description}}</div>
<div>C: {{description}}</div>
`,
providers: [
{ provide: CarService, useClass: CarService3 }
]
})
上面CarService作为车这个对象的描述,那么用不同的userClass:CarService2 ,CarService3,当然他们都是继承extends于CarService的,这就非常清楚的描述了屌丝和白富美之间的区别,这个例子就形象描述了Hierarchical injectors这个概念。
并非所有的依赖都是类。 有时候你会希望注入接口,可调用类型,字符串、函数或对象,这个时候InjectionToken上场了
import { Type } from '../type';
/**
* Creates a token that can be used in a DI Provider.
*
* Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
* runtime representation) such as when injecting an interface, callable type, array or
* parameterized type.
*
* `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
* the `Injector`. This provides additional level of type safety.
*
* ```
* interface MyInterface {...}
* var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
* // myInterface is inferred to be MyInterface.
* ```
*
* When creating an `InjectionToken`, you can optionally specify a factory function which returns
* (possibly by creating) a default value of the parameterized type `T`. This sets up the
* `InjectionToken` using this factory as a provider as if it was defined explicitly in the
* application's root injector. If the factory function, which takes zero arguments, needs to inject
* dependencies, it can do so using the `inject` function. See below for an example.
*
* Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
* overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
* mentioned above, `'root'` is the default value for `providedIn`.
*
* @usageNotes
* ### Basic Example
*
* ### Plain InjectionToken
*
* {@example core/di/ts/injector_spec.ts region='InjectionToken'}
*
* ### Tree-shakable InjectionToken
*
* {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
*
*
* @publicApi
*/
export declare class InjectionToken<T> {
protected _desc: string;
readonly ngInjectableDef: never | undefined;
constructor(_desc: string, options?: {
providedIn?: Type<any> | 'root' | null;
factory: () => T;
});
toString(): string;
}
export interface InjectableDefToken<T> extends InjectionToken<T> {
ngInjectableDef: never;
}
比如我们前端处理HTTP拦截器,
/**
* A multi-provider token which represents the array of `HttpInterceptor`s that
* are registered.
*
* @publicApi
*/
export declare const HTTP_INTERCEPTORS: InjectionToken<HttpInterceptor[]>;
export class O1Interceptorimplements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
///...
}
///...
}
export class O2Interceptorimplements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
///...
}
///...
}
export const httpInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: O1Interceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: O2Interceptor, multi: true }
];
通过这种方式,每当发起一个http请求,则自动会执行O1Interceptorimplements.intercept,O2Interceptorimplements.intercept,
比如我们定义一个项目配置文件:
/**
* 系统资源文件
*/
export interface PrjectSysResource {
resourceId?: string;
resourceName: string;
permission: string;
close: any;
}
export const DI_SYS_RESOURCE1: PrjectSysResource = {
resourceId: 't-5205-1',
resourceName: 'Java 学习-1',
permission: '',
close: () => {
console.log('Java 学习-1');
},
};
export const DI_SYS_RESOURCE2: PrjectSysResource = {
resourceId: 't-5205-2',
resourceName: 'Java 学习-2',
permission: '',
close: () => {
console.log('Java 学习-2');
},
};
// DI Token
export const SYS_RESOURCE_CONFIG = new InjectionToken<PrjectSysResource[]>('sys.resource.config');
使用:
@NgModule({
providers: [
{ provide: SYS_RESOURCE_CONFIG, useValue: DI_SYS_RESOURCE1 },
{ provide: SYS_RESOURCE_CONFIG, useValue: DI_SYS_RESOURCE2, multi: true },
{ provide: NZ_WAVE_GLOBAL_CONFIG, useValue: { disabled: false } },
]
})
export class CarService4 extends CarService2 {
constructor(
@Optional() @Inject(SYS_RESOURCE_CONFIG) private sysResource: PrjectSysResource
) {
}
getCar() {
const car = super.getCar();
car.name = '资源名称:${this.sysResource.resourceName} Chizzamm Motors, Calico UltraMax Supreme';
return car;
}
}
来自 https://zhuanlan.zhihu.com/p/86051678