Nop源碼分析一

從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);
        }

   至此實例從容器中獲取到。

相關文章
相關標籤/搜索