简介
injector是用来做参数自动注入的,例如
function fn ($http, $scope, aService) {
}
</div>
ng在运行时会把$http, $scope, aService 自动作为参数传入进行执行。
其实很容易想明白,injector做了两件事
- 缓存那些service,以后作为参数注入
- 分析参数列表,找到需要的参数注入
下面源码分析如何实现上面两件事情。
结构
createInjector -> createInternalInjector return: instanceInjector
所以 createInjector() 返回的是 instanceInjector,结构如下:
{
invoke: invoke,
instantiate: instantiate,
get: getService,
annotate: annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
}
</div>
源码分析
1. createInjector
function createInjector(modulesToLoad, strictDi) {
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
// 预先配置$provide,供loadModules中调用注册service等
providerCache = {
$provide: {
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
},
// providerInjector, instanceInjector 两个注入器
// instanceInjector对外提供service等注入,providerInjector对内提供provider获取
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() {
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
}, strictDi)),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) {
var provider = providerInjector.get(servicename + providerSuffix);
return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
}, strictDi));
// 加载模块
forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
return instanceInjector;
}
</div>
2. $provide
$provide: {
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
</div>
2.1 supportObject
用于包装方法,包装前的方法接受两个参数 (key, value),经过包装后的方法能支持传入object参数,即多个 key -> value。
function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
</div>
2.2 provider
回顾下provider、service 和 factory的使用方式
app.factory('serviceName', function(){
return {
getName: function(){},
setName: function(){}
}
});
app.service('serviceName', function(){
this.getName = function() {}
this.setName = function() {}
});
app.provider('serviceName', function($httpProvider){
// 注入$httpProvider
this.$get = function() {
return {
getName: function(){},
setName: function(){}
};
}
});
app.provider('serviceName', {
$get: function () {}
});
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
// 当provider_是fn或者array时可以将其他provider注入到参数
// 因为providerInjector.instantiate(provider_)时可以传入依赖的其他provider
// 这也是provider与service,factory方法不一样的地方
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
}
function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
function value(name, val) { return factory(name, valueFn(val)); }
</div>
最终汇总到provider的实现,将provider缓存到providerCache,供调用
跟其他不一样的就是constant的实现,分别保存到providerCache和instanceCache中,这样在定义provider还是在定义service是都能注入。
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
</div>
2.3 回顾 loadModules
function runInvokeQueue(queue) {
var i, ii;
for(i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);
// 存入queue的如格式[$provide, factory, arguments]
// 经过替换,$provide.factory.apply($provide, arguments);
// 就是调用$provid的factory,service等
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
}
</div>
2.4 decorator
示例:
module.config(function($provide) {
$provide.decorator('Mail', function($delegate) {
$delegate.addCC = function(cc) {
this.cc.push(cc);
};
return $delegate;
});
})
</div>
使用示例看出,传入的参数$delegate是原先的service实例,需要在该实例上添加方法都可以,即所谓的装饰器
源码:
function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;
origProvider.$get = function() {
// 通过上面获取的provider生成需要的service实例,再以$delegate注入到参数列表
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
};
}
</div>
3. createInternalInjector
3.1 整体结构
// 从cache中获取,没有的话调用factory进行创建,具体看getService解析
function createInternalInjector(cache, factory) {
function getService(serviceName) {
}
function invoke(fn, self, locals, serviceName){
}
function instantiate(Type, locals, serviceName) {
}
return {
// 执行fn,具有参数注入功能
invoke: invoke,
// 实例化fn, 可以参数注入
instantiate: instantiate,
// 获取provider或者service
get: getService,
// 获取方法的参数列表,供注入使用
annotate: annotate,
// 确认是否含有provider或service
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
};
}
</div>
3.2 annotate
获取fn的参数列表
// type1 function fn (a, b, c) -> ['a', 'b', 'c'] // type2 ['a', 'b', fn] -> ['a', 'b'] // type3 function fn ()

