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

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

Nop源码分析一的更多相关文章

  1. Nop源码分析三

    程序的初始化工作和Ioc工作已经做完,nop默认引擎已经初始化. 下面在回到global文件的启动方法Application_Start()中, 1,继续分析下面的代码: var dependency ...

  2. Nop源码分析二

    上文我们已经通过该行代码:var typeFinder = containerManager.Resolve<ITypeFinder>(); 从注入容器中获取到了typeFinder实例. ...

  3. PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看

    catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...

  4. 源码分析:动态分析 Linux 内核函数调用关系

    源码分析:动态分析 Linux 内核函数调用关系 时间 2015-04-22 23:56:07  泰晓科技 原文  http://www.tinylab.org/source-code-analysi ...

  5. 精尽 MyBatis 源码分析 - 基础支持层

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  6. 精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  7. 精尽MyBatis源码分析 - 插件机制

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  8. 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 百篇博客分析OpenHarmony源码 | v55.01

    百篇博客系列篇.本篇为: v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程 ...

  9. 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 百篇博客分析OpenHarmony源码 | v51.04

    百篇博客系列篇.本篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | ...

随机推荐

  1. 化繁为简 如何向老婆解释MapReduce?(转载)

    化繁为简 如何向老婆解释MapReduce? 昨天,我在Xebia印度办公室发表了一个关于MapReduce的演说.演说进行得很顺利,听众们都能够理解MapReduce的概念(根据他们的反馈).我成功 ...

  2. 代码中特殊的注释技术——TODO、FIXME和XXX的用处

    前言:今天在阅读Qt  Creator的源代码时,发现一些注释中有FIXME英文单词,用英文词典居然查不到其意义!实际上,在阅读一些开源代码时,我们常会碰到诸如:TODO.FIXME和XXX的单词,它 ...

  3. Sedgewick的红黑树

    红黑树一直是数据结构中的难点,大部分关于算法与数据结构的学习资料(包括<算法导论>)对于这部分的讲解都是上来就下定义,告诉我们红黑树这个性质那个性质,插入删除要注意1234点,但是基本没有 ...

  4. Asp.net MVC 之异常处理

    对于Asp.Net MVC 项目中,对于异常情况下,会跳转到自己定义好的页面,这时就用到了MVC中的异常过滤器(Exception Filters) (1)一旦action 方法中出现异常,异常过滤器 ...

  5. JavaScript中的Array

    Array类型是ECMAScript 用的最多的类型了,ECMAScript中的数组每一项可以保存任何类型的数据,也就是说,数组的第一个项保存字符串,用第二个保存数值,用第三个位置来保存对象.二千数据 ...

  6. overfitting过拟合

    来自:https://www.zhihu.com/question/32246256 其实不完全是噪声和假规律会造成过拟合. (1)打个形象的比方,给一群天鹅让机器来学习天鹅的特征,经过训练后,知道了 ...

  7. mysql数据库连接方式(.net)

    1.通过ado.net连接(数据库连接串中库名称为中文无法使用) 需要添加MySql.Data.dll(可通过安装mysql-connector-net-6.8.3.mis获得) 引用MySql.Da ...

  8. pH 值与曝气对硝化细菌硝化作用的影响

    http://wenku.baidu.com/view/c2723434eefdc8d376ee325d.html 摘要: 目的 探讨硝化细菌最佳工作条件,为应用和生产提供依据. 方法 通过人工调节液 ...

  9. 26. Binary Tree Maximum Path Sum

    Binary Tree Maximum Path Sum Given a binary tree, find the maximum path sum. The path may start and ...

  10. mac安装chromedriver报错

    运行提示:Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/c ...