• Nop源码分析一


    从Global.asax文件开始逐层分析Nop的架构。

    Application_Start()方法作为mvc启动的第一个方法。

    1,首先初始化一个引擎上下文,如下面的代码: EngineContext.Initialize(false);

        引擎实现了IEngine接口,该接口定义如下:

      public interface IEngine
        {
            ContainerManager ContainerManager { get; }

            void Initialize(NopConfig config);

            T Resolve<T>() where T : class;

            object Resolve(Type type);

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

       至此实例从容器中获取到。

  • 相关阅读:
    字符串,format格式化及列表的相关进阶操作---day07
    利用wiile双层循环打印各种星星---day06
    双层循环练习,pass_break_continue,和for循环---day06
    类型判断,代码块,流程控制及循环---day05
    频繁项集算法
    Unity 物体移动的理解
    Game1---游戏设计
    精读Hadamard Response论文
    java 创建线程
    Unity游戏开发面试基础知识
  • 原文地址:https://www.cnblogs.com/Alex80/p/10703016.html
Copyright © 2020-2023  润新知