今天我们来看看NopCommerce源码一个值得借鉴的设计,TypeFinder类型自动查找。它会自动去程序的bin目录或者AppDomain下查找满足指定类型的的所有类型的集合。比如:

  1. var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();

上面代码就是查找实现接口所有的类。仅可以查找指定类型,还可以获取全部的程序集,如下:

  1. typeFinder.GetAssemblies().ToArray()

利用以上两点就可以利用IoC容器对查找的类型进行遍历注册。下面是我从nopCommerce源码中找到关于IoC和TypeFinder使用的代码。

  1. builder.RegisterControllers(typeFinder.GetAssemblies().ToArray());
  1. var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();
  2. foreach (var consumer in consumers)
  3. {
  4. builder.RegisterType(consumer)
  5. .As(consumer.FindInterfaces((type, criteria) =>
  6. {
  7. var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
  8. return isMatch;
  9. }, typeof(IConsumer<>)))
  10. .InstancePerLifetimeScope();
  11. }

从上面我们知道了Nop中TypeFinder的作用,那么它又是怎么实现的呢?下面我就来说说TypeFinder的原理。同样我们来看看这部分相关代码的类图:

TypeFinder相关的类及作用:

1、ITypeFinder:类型查找抽象接口

2、AppDomainTypeFinder:在当前运行中的AppDomain中查找相关类型的集合

3、WebAppTypeFinder:在当前的web App的bin查找相关类型的集合

4、DependencyRegistrar:依赖注册

5、NopEngine:Nop引擎

接下来我们来看看这些类的核心代码及作用。

Nop.Core.Infrastructure.ITypeFinder

  1. public interface ITypeFinder
  2. {
  3. IList<Assembly> GetAssemblies();
  4. IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true);
  5. IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true);
  6. IEnumerable<Type> FindClassesOfType<T>(bool onlyConcreteClasses = true);
  7. IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true);
  8. }

Nop.Core.Infrastructure.AppDomainTypeFinder

  1. public class AppDomainTypeFinder : ITypeFinder
  2. {
  3. #region Fields
  4. private bool ignoreReflectionErrors = true;
  5. private bool loadAppDomainAssemblies = true;
  6. //忽略一些系统程序集及其它特殊程序集
  7. private string assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^AjaxControlToolkit|^Antlr3|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EntityFramework|^EPPlus|^FluentValidation|^ImageResizer|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^mvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^Telerik|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebActivator|^WebDev|^WebGrease";
  8. private string assemblyRestrictToLoadingPattern = ".*";
  9. private IList<string> assemblyNames = new List<string>();
  10. #endregion
  11. #region Methods
  12. public IEnumerable<Type> FindClassesOfType<T>(bool onlyConcreteClasses = true)
  13. {
  14. return FindClassesOfType(typeof(T), onlyConcreteClasses);
  15. }
  16. public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true)
  17. {
  18. return FindClassesOfType(assignTypeFrom, GetAssemblies(), onlyConcreteClasses);
  19. }
  20. public IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
  21. {
  22. return FindClassesOfType(typeof (T), assemblies, onlyConcreteClasses);
  23. }
  24. public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom,
  25. IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
  26. {
  27. var result = new List<Type>();
  28. try
  29. {
  30. foreach (var a in assemblies)
  31. {
  32. Type[] types = null;
  33. try
  34. {
  35. types = a.GetTypes();
  36. }
  37. catch
  38. {
  39. //Entity Framework 6 doesn't allow getting types (throws an exception)
  40. if (!ignoreReflectionErrors)
  41. {
  42. throw;
  43. }
  44. }
  45. if (types != null)
  46. {
  47. foreach (var t in types)
  48. {
  49. if (assignTypeFrom.IsAssignableFrom(t)
  50. || (assignTypeFrom.IsGenericTypeDefinition && DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
  51. {
  52. if (!t.IsInterface)
  53. {
  54. if (onlyConcreteClasses)
  55. {
  56. if (t.IsClass && !t.IsAbstract)
  57. {
  58. result.Add(t);
  59. }
  60. }
  61. else
  62. {
  63. result.Add(t);
  64. }
  65. }
  66. }
  67. }
  68. }
  69. }
  70. }
  71. catch (ReflectionTypeLoadException ex)
  72. {
  73. var msg = string.Empty;
  74. foreach (var e in ex.LoaderExceptions)
  75. msg += e.Message + Environment.NewLine;
  76. var fail = new Exception(msg, ex);
  77. Debug.WriteLine(fail.Message, fail);
  78. throw fail;
  79. }
  80. return result;
  81. }
  82. /// <summary>获取指定类型的所有实现类</summary>
  83. /// <returns>A list of assemblies that should be loaded by the Nop factory.</returns>
  84. public virtual IList<Assembly> GetAssemblies()
  85. {
  86. var addedAssemblyNames = new List<string>();
  87. var assemblies = new List<Assembly>();
  88. if (LoadAppDomainAssemblies)
  89. AddAssembliesInAppDomain(addedAssemblyNames, assemblies);
  90. AddConfiguredAssemblies(addedAssemblyNames, assemblies);
  91. return assemblies;
  92. }
  93. #endregion
  94. #region Utilities
  95. /// <summary>
  96. /// 遍历AppDomain下的所有程序集并与指定类型进行比较,如果匹配就加入要返回的List中
  97. /// </summary>
  98. /// <param name="addedAssemblyNames"></param>
  99. /// <param name="assemblies"></param>
  100. private void AddAssembliesInAppDomain(List<string> addedAssemblyNames, List<Assembly> assemblies)
  101. {
  102. foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
  103. {
  104. if (Matches(assembly.FullName))
  105. {
  106. if (!addedAssemblyNames.Contains(assembly.FullName))
  107. {
  108. assemblies.Add(assembly);
  109. addedAssemblyNames.Add(assembly.FullName);
  110. }
  111. }
  112. }
  113. }
  114. /// <summary>
  115. /// 添加特定程序集到到集合中
  116. /// </summary>
  117. /// <param name="addedAssemblyNames"></param>
  118. /// <param name="assemblies"></param>
  119. protected virtual void AddConfiguredAssemblies(List<string> addedAssemblyNames, List<Assembly> assemblies)
  120. {
  121. foreach (string assemblyName in AssemblyNames)
  122. {
  123. Assembly assembly = Assembly.Load(assemblyName);
  124. if (!addedAssemblyNames.Contains(assembly.FullName))
  125. {
  126. assemblies.Add(assembly);
  127. addedAssemblyNames.Add(assembly.FullName);
  128. }
  129. }
  130. }
  131. /// <summary>
  132. /// Check if a dll is one of the shipped dlls that we know don't need to be investigated.
  133. /// </summary>
  134. /// <param name="assemblyFullName">
  135. /// The name of the assembly to check.
  136. /// </param>
  137. /// <returns>
  138. /// True if the assembly should be loaded into Nop.
  139. /// </returns>
  140. public virtual bool Matches(string assemblyFullName)
  141. {
  142. return !Matches(assemblyFullName, AssemblySkipLoadingPattern)
  143. && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern);
  144. }
  145. /// <summary>
  146. /// Check if a dll is one of the shipped dlls that we know don't need to be investigated.
  147. /// </summary>
  148. /// <param name="assemblyFullName">
  149. /// The assembly name to match.
  150. /// </param>
  151. /// <param name="pattern">
  152. /// The regular expression pattern to match against the assembly name.
  153. /// </param>
  154. /// <returns>
  155. /// True if the pattern matches the assembly name.
  156. /// </returns>
  157. protected virtual bool Matches(string assemblyFullName, string pattern)
  158. {
  159. return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
  160. }
  161. /// <summary>
  162. /// Makes sure matching assemblies in the supplied folder are loaded in the app domain.
  163. /// </summary>
  164. /// <param name="directoryPath">
  165. /// The physical path to a directory containing dlls to load in the app domain.
  166. /// </param>
  167. protected virtual void LoadMatchingAssemblies(string directoryPath)
  168. {
  169. var loadedAssemblyNames = new List<string>();
  170. foreach (Assembly a in GetAssemblies())
  171. {
  172. loadedAssemblyNames.Add(a.FullName);
  173. }
  174. if (!Directory.Exists(directoryPath))
  175. {
  176. return;
  177. }
  178. //获取指定目录下以.dll为结尾的文件
  179. foreach (string dllPath in Directory.GetFiles(directoryPath, "*.dll"))
  180. {
  181. try
  182. {
  183. var an = AssemblyName.GetAssemblyName(dllPath);
  184. if (Matches(an.FullName) && !loadedAssemblyNames.Contains(an.FullName))
  185. {
  186. App.Load(an);//加载程序集到当前AppDomain中
  187. }
  188. //old loading stuff
  189. //Assembly a = Assembly.ReflectionOnlyLoadFrom(dllPath);
  190. //if (Matches(a.FullName) && !loadedAssemblyNames.Contains(a.FullName))
  191. //{
  192. // App.Load(a.FullName);
  193. //}
  194. }
  195. catch (BadImageFormatException ex)
  196. {
  197. Trace.TraceError(ex.ToString());
  198. }
  199. }
  200. }
  201. /// <summary>
  202. /// Does type implement generic?
  203. /// </summary>
  204. /// <param name="type"></param>
  205. /// <param name="openGeneric"></param>
  206. /// <returns></returns>
  207. protected virtual bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)
  208. {
  209. try
  210. {
  211. var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();
  212. foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))
  213. {
  214. if (!implementedInterface.IsGenericType)
  215. continue;
  216. var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
  217. return isMatch;
  218. }
  219. return false;
  220. }catch
  221. {
  222. return false;
  223. }
  224. }
  225. #endregion
  226. }

Nop.Core.Infrastructure.WebAppTypeFinder

WebAppTypeFinder是继承于类AppDomainTypeFinder

  1. public class WebAppTypeFinder : AppDomainTypeFinder
  2. {
  3. #region Fields
  4. private bool _ensureBinFolderAssembliesLoaded = true;
  5. private bool _binFolderAssembliesLoaded = false;
  6. #endregion
  7. #region Ctor
  8. public WebAppTypeFinder(NopConfig config)
  9. {
  10. this._ensureBinFolderAssembliesLoaded = config.DynamicDiscovery;
  11. }
  12. #endregion
  13. #region Properties
  14. /// <summary>
  15. /// Gets or sets wether assemblies in the bin folder of the web application should be specificly checked for beeing loaded on application load. This is need in situations where plugins need to be loaded in the AppDomain after the application been reloaded.
  16. /// </summary>
  17. public bool EnsureBinFolderAssembliesLoaded
  18. {
  19. get { return _ensureBinFolderAssembliesLoaded; }
  20. set { _ensureBinFolderAssembliesLoaded = value; }
  21. }
  22. #endregion
  23. #region Methods
  24. /// <summary>
  25. /// Gets a physical disk path of \Bin directory
  26. /// </summary>
  27. /// <returns>The physical path. E.g. "c:\inetpub\wwwroot\bin"</returns>
  28. public virtual string GetBinDirectory()
  29. {
  30. if (HostingEnvironment.IsHosted)
  31. {
  32. //hosted
  33. return HttpRuntime.BinDirectory;
  34. }
  35. else
  36. {
  37. //not hosted. For example, run either in unit tests
  38. return AppDomain.CurrentDomain.BaseDirectory;
  39. }
  40. }
  41. public override IList<Assembly> GetAssemblies()
  42. {
  43. if (this.EnsureBinFolderAssembliesLoaded && !_binFolderAssembliesLoaded)
  44. {
  45. _binFolderAssembliesLoaded = true;
  46. string binPath = GetBinDirectory();
  47. //binPath = _webHelper.MapPath("~/bin");
  48. LoadMatchingAssemblies(binPath);
  49. }
  50. return base.GetAssemblies();
  51. }
  52. #endregion
  53. }

在Nop.Core.Infrastructure.NopEngine类中有以下方法:

  1. protected virtual void RegisterDependencies(NopConfig config)
  2. {
  3. var builder = new ContainerBuilder();
  4. var container = builder.Build();
  5. //we create new instance of ContainerBuilder
  6. //because Build() or Update() method can only be called once on a ContainerBuilder.
  7. //dependencies
  8. var typeFinder = new WebAppTypeFinder(config);
  9. builder = new ContainerBuilder();
  10. builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
  11. builder.RegisterInstance(this).As<IEngine>().SingleInstance();
  12. //ITypeFinder接口用WebAppTypeFinder的单例对象注册绑定
  13. builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
  14. builder.Update(container);
  15. //register dependencies provided by other assemblies
  16. builder = new ContainerBuilder();
  17. var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
  18. var drInstances = new List<IDependencyRegistrar>();
  19. foreach (var drType in drTypes)
  20. drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
  21. //sort
  22. drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
  23. foreach (var dependencyRegistrar in drInstances)
  24. dependencyRegistrar.Register(builder, typeFinder);
  25. builder.Update(container);
  26. this._containerManager = new ContainerManager(container);
  27. //set dependency resolver
  28. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
  29. }

可以看到上面 typeFinder.FindClassesOfType<IDependencyRegistrar>(),查找依赖注入抽象接口的IDependencyRegistrar的全部实现类型的集合,并依次调用其方法Register。

Nop依赖注入相关原理分析看看我以前的文章NopCommerce源码架构详解--Autofac依赖注入分析

同样我们在Nop.Web.Framework.DependencyRegistrar看到下面使用ITypeFinder注册依赖对象,如下:

  1. public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
  2. {
  3. //...省略其它代码
  4. //controllers
  5. builder.RegisterControllers(typeFinder.GetAssemblies().ToArray());
  6. //...省略其它代码
  7. //Register event consumers
  8. var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();
  9. foreach (var consumer in consumers)
  10. {
  11. builder.RegisterType(consumer)
  12. .As(consumer.FindInterfaces((type, criteria) =>
  13. {
  14. var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
  15. return isMatch;
  16. }, typeof(IConsumer<>)))
  17. .InstancePerLifetimeScope();
  18. }
  19. }

蓝狐软件工作室 » NopCommerce源码架构详解--TypeFinder程序集类型自动查找及操作相关源码分析

NopCommerce源码架构详解--TypeFinder程序集类型自动查找及操作相关源码分析相关推荐

  1. LNMP架构详解(2)——Mysql、PHP、Nginx源码编译过程

    前言 本文将介绍LNMP架构中Mysql.PHP.Nginx的源码编译过程:这时有人不仅会问:在我们使用的Linux系统中,可以从yum源中获得mysql.php,为什么要进行如此漫长复杂的过程进行编 ...

  2. linux syslogd 源码,syslogd 详解二

    相关博文: syslogd 详解一 syslogd 详解三 1. 前言 上一篇博文中详细了分析了syslogd的架构,解析了syslogd的调用过程,以及syslog.conf 的详细使用方法,这一篇 ...

  3. Android 源码编译详解【合集篇】

    Android 源码编译详解[一]:服务器硬件配置及机型推荐 做 Android系统开发多年,开发环境都是入职就搭建好了,入职时拿个账号密码就直接开始搞开发了,年初换了新公司,所有的项目都是刚起步,一 ...

  4. Android四大组件之bindService源码实现详解

        Android四大组件之bindService源码实现详解 Android四大组件源码实现详解系列博客目录: Android应用进程创建流程大揭秘 Android四大组件之bindServic ...

  5. jsp漂亮的登录界面源码_【案例+源码】详解MVC框架模式及其应用

    案例+源码]详解MVC框架模式及其应用 写在开头: 首先我们需要知道,框架模式.模式.开发模式是三种不同的概念,但他们的目的都一样:解耦! 1.关于MVC框架模型 MVC是三个单词的缩写: M,Mod ...

  6. 详解非局部均值滤波原理以及用MATLAB源码实现

    详解非局部均值滤波原理以及用MATLAB源码实现 序言 均值滤波.中值滤波.高斯滤波在滤除噪声的过程中,无可避免的使图像的边缘细节和纹理信息所被滤除.针对此问题,Buades[1]等人提出了非局部均值 ...

  7. 使用Gin框架集成JWT,源码、详解、面试问题

    使用Gin框架集成JWT,源码.详解.面试问题 一.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). ...

  8. 区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-熊丽兵-专题视频课程...

    区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-103人已学习 课程介绍         区块链开发技术进阶-深入详解以太坊智能合约语言 solidity视频培训教程:本课程是 ...

  9. java调用webservice_笃学私教:Java开发网站架构演变过程-从单体应用到微服务架构详解...

    原标题:笃学私教:Java开发网站架构演变过程-从单体应用到微服务架构详解 Java开发网站架构演变过程,到目前为止,大致分为5个阶段,分别为单体架构.集群架构.分布式架构.SOA架构和微服务架构.下 ...

  10. Nginx 架构详解

    Nginx 架构详解 nginx的下篇将会更加深入的介绍nginx的实现原理.上一章,我们了解到了如何设计一个高性能服务器,那这一章将会开始讲解,nginx是如何一步一步实现高性能服务器的. Ngin ...

最新文章

  1. matlab 2010无法运行程序,matalb r2010a安装后打开出现一系列警告,无法运行,哪位大神帮...
  2. win7下设置cmd操作mysql的环境变量
  3. glance image-create
  4. IntelliJ IDEA 使用教程(2019图文版) -- 从入门到上瘾
  5. 利用MatConvNet进行孪生多分支网络设计
  6. C语言实现离散余弦变换(DCT)并用MATLAB和Python验证
  7. python 函数的参数对应
  8. 为什么程序员更喜欢用google搜索? 因为正经!
  9. 同时多次调用存储规程_本体技术视点 | 神奇的Merkle树是如何实现存储层优化的?...
  10. 相位测试音频mp3_苹果AirPods MAX耳机音质一大短板在哪里?蓝牙AAC编码品质讨论与测试 「Soomal」...
  11. LNMP环境部署----之Mysql安装部署
  12. LREC'22 | 机器翻译中细粒度领域自适应的数据集和基准实验
  13. 指针的意义和linux的内存回收艺术
  14. phpMyAdmin创建数据库无权限解决方案
  15. 设为首页、加入收藏及保存到桌面的JS代码
  16. win10下 你需要来自trustedinstaller的权限 修改权限
  17. Ubuntu 环境下 vim 打造成 IDE
  18. java登陆密码加密怎么做,Java如何实现密码加密
  19. mysql启动报没有发现index,log_bin.index not found 启动报错解决
  20. java程序调用时的调用规则,Java程序调用ILog规则出错

热门文章

  1. 进制的概念与转换(二进制、十进制、八进制、十六进制)
  2. 利用人性做大闸蟹,给予客户特殊的身份优越感,思维决定财富!
  3. oracle数据库表的一些基本处理
  4. linux_study_1
  5. 数据结构与算法分析java语言描述 严蔚敏翻译_重读数据结构——严蔚敏C语言版...
  6. python 实现微信自动回复(自动聊天)
  7. php单页菜单,CSS3单页切换导航菜单界面设计的实现详解
  8. 视频会议中的AEC、AGC、ANS是什么?
  9. Flink_Flink ON YARN containerized.heap-cutoff-min 内存调整
  10. vue 用webpack打包文件名添加版本号