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);
}
至此实例从容器中获取到。
Nop源码分析一的更多相关文章
- Nop源码分析三
程序的初始化工作和Ioc工作已经做完,nop默认引擎已经初始化. 下面在回到global文件的启动方法Application_Start()中, 1,继续分析下面的代码: var dependency ...
- Nop源码分析二
上文我们已经通过该行代码:var typeFinder = containerManager.Resolve<ITypeFinder>(); 从注入容器中获取到了typeFinder实例. ...
- PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看
catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...
- 源码分析:动态分析 Linux 内核函数调用关系
源码分析:动态分析 Linux 内核函数调用关系 时间 2015-04-22 23:56:07 泰晓科技 原文 http://www.tinylab.org/source-code-analysi ...
- 精尽 MyBatis 源码分析 - 基础支持层
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - 插件机制
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 百篇博客分析OpenHarmony源码 | v55.01
百篇博客系列篇.本篇为: v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程 ...
- 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 百篇博客分析OpenHarmony源码 | v51.04
百篇博客系列篇.本篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | ...
随机推荐
- JavaScript学习中的挑战
当人们尝试学习 JavaScript , 或者其他编程技术的时候,常常会遇到同样的挑战: 有些概念容易混淆,特别是当你学习过其他语言的时候.很难找到学习的时间(有时候是动力).一旦当你理解了一些东西的 ...
- 使用 .bash_profile与.bashrc修改字符集
发现终端设置为UTF8显示以后 svn打印终端就一直乱码, 是用户字符集的原因 有人建议 修改.bashrc 有人建议修改~/.bash_profile 搜索了下区别 /etc/profile:此文件 ...
- javascript获取iframe框架中页面document对象,获取子页面里面的内容,iframe获取父页面的元素,
javascript获取iframe框架中,加载的页面document对象 因为浏览器安全限制,对跨域访问的页面,其document对象无法读取.设置属性 function getDocument(i ...
- jQuery入门级part.2
一,事件编程 基本事件: blur(fn) 当失去焦点时 change(fn) 当内容发生改变时 click(fn) 当鼠标单击时 dblclick(fn) 当鼠标双击时 focus ...
- 【巩固】JS获取时间的一些基础知识
就是一个new Date()对象,要注意的有以下几点; 直接给oDate对象设置年月日时分秒的时候要分成两步,oDate.setFullYear()接受三个参数分别是年月日,注意月份是从0开始计一月的 ...
- Navicat(服务器对象) -2之MySQL 或 MariaDB 对象
MySQL 或 MariaDB 对象 http://www.navicat.com.cn/manual/online_manual/cn/navicat/win_manual/index.html 要 ...
- Java为什么会引入及如何使用Unsafe
综述 sun.misc.Unsafe至少从2004年Java1.4开始就存在于Java中了.在Java9中,为了提高JVM的可维护性,Unsafe和许多其他的东西一起都被作为内部使用类隐藏起来了.但是 ...
- 在Spring的bean中注入HttpServletRequest解密
我们可以在Spring的bean中轻松的注入HttpServletRequest,使用@Autowired HttpServletRequest request;就可以了. 但是,为什么我们可以直接这 ...
- 【解决】SharePoint外部列表保存的日期/时间值不正确
[问题描述]: 在SharePoint中创建一个外部列表后,通过工作流或直接通过外部列表中的新增向外部列表添加数据项.通过外部列表或数据库查看添加的数据项时发现日期类型字段的值都不正确,像是差了若干个 ...
- java获取服务器所有信息
package com.sinosoft.outher.listener; import java.net.InetAddress;import java.net.UnknownHostExcepti ...