angularjs依赖注入原理,angular js依赖注入是通过 方式实现的
本文带你聊聊Angular,介绍一下依赖注入的基本概念。希望对你有帮助!
作为一个为“大型前端项目”设计的前端框架,Angular其实有很多设计值得借鉴和学习。本系列主要用于研究这些设计和功能的实现原理。本文重点介绍Angular的最大特点,——依赖注入。首先,介绍了角度依赖注入系统的一些基本概念。
依赖注入
既然要介绍Angular框架的依赖注入设计,首先要为依赖注入的基本概念做铺垫。我们经常混淆依赖反转原则(DIP)、控制反转(IoC)和依赖注入(DI)的概念,这里简单介绍一下。【相关教程推荐:《angular教程》】
依赖倒置原则、控制反转、依赖注入
低耦合高内聚大概是每个系统的设计目标之一,也因此产生了很多设计模式和思想,包括依赖反演原理和控制反演的设计思想。
(1) 依赖倒置原则(DIP)。
依赖性倒置原则的最初定义是:
高层模块不应该依赖于低层模块,但两者都应该依赖于它们的抽象;抽象不应该依赖细节,细节应该依赖抽象。简单来说,模块之间不应该直接相互依赖,而是依赖于一个抽象规则(接口或者时态抽象类)。
(2) 控制反转(IoC)。
控制定义为:模块之间的依赖关系从程序内部提到外部来实例化管理。也就是说,当一个对象被创建时,它由一个外部实体控制,该外部实体管理系统中的所有对象,并将它的依赖对象的引用传递(注入)给它。
实现控制反转主要有两种方式:
依赖注入:被动接收依赖对象依赖查找:主动要求依赖对象(3) 依赖注入。
依赖注入是控制反转最常用的技术。
依赖反转和控制反转相辅相成,经常可以一起使用,可以有效降低模块之间的耦合。
Angular 中的依赖注入
在Angular中,还使用了依赖注入的技术。在实例化一个类时,DI框架会为其提供该类声明的依赖关系(依赖关系:指该类需要执行其功能时所需的服务或对象)。
Angular中的依赖注入基本上是围绕组件或模块进行的,主要用于为新创建的组件提供依赖。
Angular中的主要依赖注入机制是注入器机制:
应用程序所需的任何依赖项都必须向应用程序的注入器注册一个提供者,以便注入器可以使用这个提供者来创建一个新实例。Angular将在启动期间创建一个完整的应用程序级注入器和其他所需的注入器。主要涉及两个概念,即Injector 注入器和Provider 提供商。让我们来看看。
Injector 注入器
注射器用于创建依赖关系。它将维护一个容器来管理这些依赖项,并尽可能地重用它们。注入器将提供依赖的单例,并将这个单例对象注入多个组件。
显然,作为创建、管理和维护依赖关系的容器,注入器的功能很简单:创建、获取和管理依赖关系实例。我们还可以从抽象类Injector的源代码中看到:
导出抽象类注入器{
//找不到依赖项
static THROW _ IF _ NOT _ FOUND=THROW _ IF _ NOT _ FOUND;
//NullInjector是树的顶部
//如果您在树中一直向上寻找nullInjector中的服务,您将收到一条错误消息,或者对于@Optional(),返回null。
static NULL:Injector=new NULL Injector();
//根据提供的标记从注入器中检索实例
抽象getT(
token:TypeT abstract TypeT injection token,
notFoundValue?T,
旗帜?注入标志
):T;
//创建提供一个或多个依赖项的新注入器实例
静态创建(选项:{
providers:static provider[];
父母?注射器;
名字?字符串;
}):注射器;
//define injectible用于构造InjectableDef。
//它定义了DI系统将如何构造令牌,以及它将在哪个注入器中可用。
静态prov=defineInjectable({
令牌:注射器,
提供“任何”作为任何,
//注入生成的指令:从当前活动的注入器注入令牌。
工厂:()=inject(INJECTOR),
});
static _ _ NG _ ELEMENT _ ID _ _=injector markers。注射器;
}即我们可以将需要共享的依赖实例添加到注入器中,通过Token查询检索注入器来获取对应的依赖实例。
注意Angular中的注入器是分层的,所以寻找依赖关系的过程也是向上遍历注入器树的过程。
这是因为在Angular中,应用程序是以模块化的方式组织的。详情请参考5。模块化组织。一般来说,页面的DOM是以html为根节点的树形结构。基于此,Angular应用中的组件和模块也伴随着树形结构。
Injector服务于组件和模块,也是挂载和模块和组织的树形结构。因此,注入器也分为模块级和组件级,可以分别为组件和模块提供依赖关系的具体实例。注入器是可继承的,这意味着如果指定的注入器无法解析依赖项,它将请求父注入器解析它。从上面创建注射器的代码中我们也可以看出:
//创建一个新的注入器实例,该实例可以传递给父注入器
静态创建(选项:{providers: StaticProvider[],parent?注射器,名称?string}):注射器;在一个注入器的范围内,服务是单一的。也就是说,在指定的注入器中最多有一个服务实例。如果您不想在任何地方都使用同一个服务实例,您可以通过注册多个注入器并根据需要将它们关联到组件和模块中,按需共享服务依赖关系的实例。
我们可以看到,当创建一个新的注入器实例时,传入的参数包括Provider。这是因为Injector不直接创建依赖项,而是通过Provider来创建。每个注入器将维护一个提供者列表,并根据组件或其他服务的需要使用它们来提供服务实例。
Provider 提供者
提供者用于告诉注入者如何获取或创建依赖关系。为了让注入器创建服务(或提供其他类型的依赖项),必须为注入器配置一个提供者。
提供者对象定义了如何获得与DI令牌相关联的可注入依赖项,注入器将使用这个提供者来创建它所依赖的类的实例。
提供者有很多种类型,它们的具体定义可以从官方文档中读取:
导出类型提供程序=
类型提供者
值提供者
ClassProvider
建筑商
现有提供者
工厂供应商
any[];提供者的解析过程如下:
函数resolveReflectiveFactory(
提供者:标准化提供者
):ResolvedReflectiveFactory {
让factoryFn:函数;
let resolved steps:reflective dependency[];
if (provider.useClass) {
//使用类来提供依赖关系
const use class=resolveForwardRef(provider . use class);
factory fn=reflector . factory(use class);
resolved steps=_ dependencies for(use class);
} else if (provider.useExisting) {
//使用现有的依赖关系
factory fn=(aliasInstance:any)=aliasInstance;
//从标记中获取特定的依赖关系。
resolvedDeps=[
reflective dependency . from key(reflective key . get(provider . use existing)),
];
} else if (provider.useFactory) {
//使用工厂方法提供依赖关系
factory fn=provider . use factory;
resolved deps=construct dependencies(provider . use factory,provider . deps);
}否则{
//使用特定于提供程序的值作为依赖项
factory fn=()=provider . use value;
resolvedDeps=_ EMPTY _ LIST
}
//
返回新的ResolvedReflectiveFactory(factory fn,resolved EPS);
}根据提供者的不同类型,经过解析,得到注入器使用的提供者的内部解析表示:
导出接口ResolvedReflectiveProvider {
//密钥,包括系统范围的唯一id和一个令牌
key:reflective key;
//可以返回键表示的对象的实例的工厂函数
resolved factories:resolved reflective factory[];
//指示提供程序是多提供程序还是常规提供程序
multi provider:boolean;
}提供者可以是服务类ClassProvider本身。如果服务类被指定为提供者令牌,那么注入器的默认行为是用new。
Angular 中的依赖注入服务
在Angular中,服务是一个带有@ Injectable decorator的类,它封装了非UI逻辑和可以在应用程序中重用的代码。Angular将组件从服务中分离出来,以提高模块化和可重用性。
用@Injectable标记一个类,保证编译器在注入类时会生成必要的元数据(元数据在Angular中也是很重要的一部分)来创建类的依赖关系。
@ Injectable Decorator的类在编译后会得到Angular injectable对象:
//根据角度可注入对象的可注入元数据编译角度可注入对象,并对结果进行补丁。
导出函数compileInjectable(类型:Typeany,srcMeta?可注射):无效{
//这个编译过程依赖于@angular/compiler
//请参考编译器中CompileFactoryFunction CompileInjectable的实现。
}Angular中的可注入对象(InjectableDef)定义了DI系统将如何构造令牌以及哪些注入器(如果有)可用:
导出接口InjectableDefT {
//指定给定类型属于特定的注入器,包括root/platform/any/null和特定的NgModule。
根 平台 any null
//此定义所属的标记
token:未知;
//创建可注入实例时要执行的工厂方法
工厂:(t?type any)=T;
//存储没有显式注入器的可注入实例的位置。
值:T 未定义;
}当使用@ Injectable()的providedIn时,优化工具可以执行摇树优化,从而删除应用程序中未使用的服务,以减小包的大小。
总结
本文简要介绍了角度依赖注入系统中的几个关键概念,包括注入器、提供器和可注入器。
对于注射者、提供者和注射服务,我们可以简单地这样理解:
注入器用于创建依赖关系。它将维护一个容器来管理这些依赖项,并尽可能地重用它们。
注射器中的依赖服务只有一个实例。
注入器需要使用提供者来管理依赖关系,并通过令牌(DI令牌)将它们关联起来。
提供者用于高速注入器应该如何获取或创建依赖关系。
将根据元数据编译可注入的服务类,以获得可注入的对象,该对象可用于创建实例。
有关编程的更多信息,请访问:编程入门!这就是角度依赖注入系统中基本概念的细节。请多关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。