angular源码分析2-依赖注入实现

场景实例

如上代码,run方法依赖注入testervice服务,app模块加载执行run方法的传入的函数时,注入testService实例化的单例对象,在函数执行时,获取获取/设置该对象的属性值,或执行该对象的属性方法。在执行run方法传递的函数时,打印输出a。

下面先看看数据的流动过程,然后分析代码的实现。在js中皆为数据,function也是数据类型的一种。在这里,function和其他数据类型一样,也理解为数据类型。

数据流动

上面的js文件加载后,通过调用angular.module('app')方法获取模块app的模块对象,调用run方法把function(testProvider){console.log (testProvider.a);})放入模块的对象的_runBlocks队列中,然后返回模块对象。调用模块对象的service方法把['$provide','provider',Arguments(2)]放入模块对象的_invokeQueue队列中,其中Argument(2)为调用第8行的 service传入的参数的argumens。

modules.app._runBlocks = [... ,function(testProvider){console.log (testProvider.a);}), ...]

modules.app._invokeQueue = [... ,['$provide','provider',Arguments(2)], ...]

在加载模块的过程中, 会执行modules.app._invokeQueue队列和执行modules.app._runBlocks队列中的函数。

执行完modules.app._invokeQueue后,会把队列的元素转化处理缓存存储在providerCache对象中,

providerCache.testProviderProvider = {
    $get:function(){
        return {a:'a'};
    }
}

在执行modules.app._runBlocks队列中的函数时,会执行如下函数:

function(testProvider){
    console.log(testProvider.a);
}

结果输出a。

在执行上面的函数时,先获取testProvider服务,从provideCache.testProviderProvider获得{a:'a'}对象,并且存储在instanceCache对象中,即

instanceCache.testProvider = {
    a : 'a'
}

执行上面函数时,通过apply方法把testProvider对象作为实参传入,函数内部可操作该对象。若下次需依赖注入 testProvider,直接从instanceCache获取该对象。


代码分析

第3875行instanceCache对象用于存储与依赖注入有关的信息。用于实例化服务单例对象和缓存服务对象。第3976行到3980行创建了$injector服务,并且挂载在instanceCache对象上,即instanceCache.$injector。利用闭包特性,服务$injector可以访问第3977行createInternalInjector传的实参。下面看一下,是如何创建$injector服务的。

第4114行到第4135行createInternalInjector函数用于创建$injector服务。在第3977行到第3980行调用该函数后,返回从第4126行到第4134行包含的对象,这个对象即$injector服务。其中invoke函数用于执行使用依赖注入的函数和获取依赖服务的对象,如function(testProvider){}依赖testProvider的函数。get函数用于根据函数的参数的名字获取相应的服务对象,如该对象没有被实例化过,实例化对象并缓存在instanceCache对象中,并返回实例化后的对象。如果依赖注入的对象实例化过,直接从缓存中对象获取并返回。annotate函数返回函数所依赖的依赖服务的形参名组成的数组。

第4114行到第4136行的getService用于根据服务名获取服务实例。

第4138行到第4164行的invoke函数用于执行依赖注入的函数。如上面的函数function(testProvider){}。先获取testProvider服务,然后把testProvider服务的单例对象,作为该函数的实参传入,并执行这个函数。第 4144行获取fn的依赖注入的服务名字,即['testProvider']。第4147行到4157行用于获取函数fn依赖的服务。第4163行把依赖的服务传入函数,并且执行该函数。

providerCache与instanceCache 

providerCache缓存对象:

providerCache = {
    $provide: {
            provider: supportObject(provider),
            factory: supportObject(factory),
            service: supportObject(service),
            value: supportObject(value),
            constant: supportObject(constant),
            decorator: decorator
          },
    $injector:{},

    //模块加载时,缓存的一些经过处理后的服务,不是最终的服务对象,
    //生成的最终对象缓存在instanceCache对象中
    testProviderProvider:{
       $get: function (){
            {a : 'a'}
       }
   },
   ...
}

instanceCache对象:

instanceCache = {
    $injector: {
         invoke: invoke,
         instantiate: instantiate,
         get: getService,
         annotate: annotate,
         has: function(name) {
             return providerCache.hasOwnProperty(name + 
                providerSuffix) || cache.hasOwnProperty(name);
         }
    },
   
    //缓存实例化对象
    testProvider: {
        a : 'a'
    }
    ...
}

providerCache对象与instanceCache对象贯穿于整个框架,是框架的核心数据。

providerCache对象主要用于模块加载时,操作和缓存注入的provider,service ,factory等服务。

instanceCache对象借助于providerCache对象实现依赖服务的管理。实例化服务,并缓存服务单例对象。

原文地址:https://www.cnblogs.com/fe-huahai/p/7011418.html