從Global.asax文件開始逐層分析Nop的架構。web
Application_Start()方法做爲mvc啓動的第一個方法。緩存
1,首先初始化一個引擎上下文,以下面的代碼: EngineContext.Initialize(false);架構
引擎實現了IEngine接口,該接口定義以下:mvc
public interface IEngine
{
ContainerManager ContainerManager { get; }函數
void Initialize(NopConfig config);ui
T Resolve<T>() where T : class;this
object Resolve(Type type);spa
T[] ResolveAll<T>();
}對象
2,在 EngineContext.Initialize(false)方法中具體作了以下工做:繼承
首先是Singleton<IEngine>.Instance == null判斷,Singleton<IEngine>.Instance是一個泛型單例模式,定義以下:Singleton<T> : Singleton,在singleton中定義了一個IDictionary<Type, object>集合,每次爲instance賦值的時候,都會保存到這個集合中,從而緩存到整個應用程序中。
3,此行代碼正是對實例賦值: Singleton<IEngine>.Instance = CreateEngineInstance(config)
接下來分析 CreateEngineInstance(config)是如何獲取到引擎的實例的:
(1)參數config是NopConfig的一個實例,是經過讀取web.config中節點NopConfig的信息,比較好理解。
(2)在配置文件中EngineType這個值是「」,因此就實例化一個默認的引擎: NopEngine。
(3)在實例化 NopEngine引擎時,調用了public NopEngine(EventBroker broker, ContainerConfigurer configurer)構造函數。
參數類型 broker=EventBroker.Instance; 一個http請求過程當中的事件註冊類,針對的事件主要是http請求過程當中事件。
configurer=new ContainerConfigurer(); 實例化一個配置服務NOP使用控制反轉容器
(4)EventBroker.Instance參數分析:經過該方式:Singleton<EventBroker>.Instance獲取一個EventBroker實例。
4,經過構造以上三個參數,程序開始執行 InitializeContainer(configurer, broker, config),此過程是依賴注入,利用Autofac第三方類庫。
代碼分析:
(1) var builder = new ContainerBuilder(); 建立一個依賴注入的容器構造器,全部的注入全是由它來完成。
(2) _containerManager = new ContainerManager(builder.Build()); builder.Build() autofac來建立一個容器,並將該容器傳遞到nop自定義的容器管理類的構 造 函數中。ContainerManager 管理着注入方式的各類狀況。
(3)接下來調用 configurer.Configure(this, _containerManager, broker, config);這個方法是配置依賴注入核心,在該方法中把應用程序的全部須要注入的分批註入。
A:注入了幾個全局的配置,以下代碼,
containerManager.AddComponentInstance<NopConfig>(configuration, "nop.configuration");
containerManager.AddComponentInstance<IEngine>(engine, "nop.engine");
containerManager.AddComponentInstance<ContainerConfigurer>(this, "nop.containerConfigurer");
來具體分析 containerManager.AddComponentInstance<IEngine>(engine, "nop.engine");者行代碼主要作了什麼工做。
調用方法的簽名AddComponentInstance<TService>(object instance, string key = "", ComponentLifeStyle lifeStyle = ComponentLifeStyle.Singleton)
參數說明:instance: 實例名,也就是須要注入的實例,是一個object類型,也就意味着能夠傳入一切類型。
key:注入的鍵值名稱,
lifeStyle:實例在容器中的生命週期,此參數配置爲了單例,意味着在整個應用程序的生命週期中只有一個該實例。
接下來調用 UpdateContainer(x =>
{
var registration = x.RegisterInstance(instance).Keyed(key, service).As(service).PerLifeStyle(lifeStyle);
}); UpdateContainer方法傳遞一個Action<ContainerBuilder>的委託。
x.RegisterInstance(instance).Keyed(key, service).As(service).PerLifeStyle(lifeStyle);這行代碼是真正注入的過程。
註冊完以後要更新一下容器,以下面代碼:
builder.Update(_container);
B: 註冊一個 containerManager.AddComponent<ITypeFinder, WebAppTypeFinder>("nop.typeFinder");WebAppTypeFinder類的做用是經過程序集反射出咱們想要注入的內容。 該方法會調用 AddComponent(typeof(TService), typeof(TImplementation), key, lifeStyle);
而後調用
UpdateContainer(x =>
{
var serviceTypes = new List<Type> { service }; //把接口放到一個list<type>的集合中。
if (service.IsGenericType) //若是是泛型接口,進行下面的操做。
{
var temp = x.RegisterGeneric(implementation).As(
serviceTypes.ToArray()).PerLifeStyle(lifeStyle);
if (!string.IsNullOrEmpty(key))
{
temp.Keyed(key, service);
}
}
else //不是泛型接口,進行下面的操做。
{
var temp = x.RegisterType(implementation).As(
serviceTypes.ToArray()).PerLifeStyle(lifeStyle);
if (!string.IsNullOrEmpty(key))
{
temp.Keyed(key, service); //key值和list<type>相關聯。
}
}
});
C: 接下來咱們就開始用咱們剛剛注入到容器中的類。一下代碼是調用的方法:
var typeFinder = containerManager.Resolve<ITypeFinder>();
代碼分析:Resolve
public T Resolve<T>(string key = "") where T : class
{
if (string.IsNullOrEmpty(key)) //key值爲空的狀況下。會調用下面的方法。
{
return Scope().Resolve<T>();
}
return Scope().ResolveKeyed<T>(key);
}
D:分析Scope().Resolve<T>() 方法是如何從容器中獲得的實例。
public ILifetimeScope Scope() //獲取一個容器生命週期範圍。
{
try
{
return AutofacRequestLifetimeHttpModule.GetLifetimeScope(Container, null); //
}
catch
{
return Container;
}
}
方法AutofacRequestLifetimeHttpModule.GetLifetimeScope(Container, null)以下:
public static ILifetimeScope GetLifetimeScope(ILifetimeScope container, Action<ContainerBuilder> configurationAction)
{
//little hack here to get dependencies when HttpContext is not available
if (HttpContext.Current != null)
{
return LifetimeScope ?? (LifetimeScope = InitializeLifetimeScope(configurationAction, container));
}
else
{
//throw new InvalidOperationException("HttpContextNotAvailable");
return InitializeLifetimeScope(configurationAction, container);
}
}
最後程序返回一個ILifetimeScope接口的實例。 接口繼承關係:ILifetimeScope : IComponentContext
調用該接口的Resolve<T>()方法返回真正的對象。
方法實現代碼:IComponentContext的擴展方法。
public static TService Resolve<TService>(this IComponentContext context)
{
return Resolve<TService>(context, NoParameters);
}
至此實例從容器中獲取到。