NopCommerce源码架构详解--Autofac依赖注入分析

NopCommerce整个代码里面都贯彻了一个面向接口编程的思想。nopCommerce商城系统是通过Autofac对接口依赖的实现进行依赖注入的。今天我们就来分析一下里面的源码,学习一下Nop在依赖注入方面设计思想,希望在以后的架构设计中对你有启发和帮助。

下面是Nop依赖注入相关类图。

可以看到这里面相关的类为

mvcApplication

IEngine,NopEngine

EngineContext

IDependencyRegistrar,DependencyRegistrar

下面我们再来看看这些类的核心代码。

我们打开Nop.Web项目的所有的Controller源码,可以看到基本上都是通过构造函数引用抽象的接口。如CustomerController的构造函数的参数类型都是某一个接口,如下图:

那我们要想看这些接口到底依赖的是哪一个真正的实现类呢?

在项目Nop.Web.Framework中有一个类DependencyRegistrar,其作用就是调用Autofac相关的API进行依赖注入,我们只要打开这个类文件,搜索一个指定的接口,就可以找到它依赖的具体类。例如,我们想看到ICategoryService接口是依赖哪一个实现,在这个类中搜索ICategoryService,会找到下面的代码:

 
 
  1. builder.RegisterType<CategoryService>().As<ICategoryService>().InstancePerLifetimeScope();

可以看到这个接口对应的实现为为CategoryService(Nop.Services.Catalog命名空间下的类CategoryService)。

下面我们来看看Nop在网站启动是怎么调用这个DependencyRegistrar类呢?

在项目Nop.Web也就是前台的起始项目有一个文件Global.asax里有一个函数Application_Start,这函数的意义这里就不用说了,我相信学过ASP.NET同学都知道它的作用,下面是函数Application_Start的完整代码:

 
 
  1. protected void Application_Start()
  2. {
  3. //初始化上下文引擎
  4. EngineContext.Initialize(false);
  5. //model binders
  6. ModelBinders.Binders.Add(typeof(BaseNopModel), new NopModelBinder());
  7. bool databaseInstalled = DataSettingsHelper.DatabaseIsInstalled();
  8. if (databaseInstalled)
  9. {
  10. //remove all view engines
  11. ViewEngines.Engines.Clear();
  12. //except the themeable razor view engine we use
  13. ViewEngines.Engines.Add(new ThemeableRazorViewEngine());
  14. }
  15. //Add some functionality on top of the default ModelMetadataProvider
  16. ModelMetadataProviders.Current = new NopMetadataProvider();
  17. //Registering some regular mvc stuff
  18. AreaRegistration.RegisterAllAreas();
  19. RegisterRoutes(RouteTable.Routes);
  20. //fluent validation
  21. DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
  22. ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new NopValidatorFactory()));
  23. //start scheduled tasks
  24. if (databaseInstalled)
  25. {
  26. TaskManager.Instance.Initialize();
  27. TaskManager.Instance.Start();
  28. }
  29. //log application start
  30. if (databaseInstalled)
  31. {
  32. try
  33. {
  34. //log
  35. var logger = EngineContext.Current.Resolve<ILogger>();
  36. logger.Information("Application started", null, null);
  37. }
  38. catch (Exception)
  39. {
  40. //don't throw new exception if occurs
  41. }
  42. }
  43. }

里面有第一行代码就调用了上下文引擎初始化。

 
 
  1. EngineContext.Initialize(false);

下面我们来看看这个EngineContext的静态方法Initialize:

 
 
  1. [MethodImpl(MethodImplOptions.Synchronized)]
  2. public static IEngine Initialize(bool forceRecreate)
  3. {
  4. if (Singleton<IEngine>.Instance == null || forceRecreate)
  5. {
  6. var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
  7. Singleton<IEngine>.Instance = CreateEngineInstance(config);
  8. Singleton<IEngine>.Instance.Initialize(config);
  9. }
  10. return Singleton<IEngine>.Instance;
  11. }
 
 
  1. protected static IEngine CreateEngineInstance(NopConfig config)
  2. {
  3. if (config != null && !string.IsNullOrEmpty(config.EngineType))
  4. {
  5. var engineType = Type.GetType(config.EngineType);
  6. if (engineType == null)
  7. throw new ConfigurationErrorsException("The type '" + config.EngineType + "' could not be found. Please check the configuration at /configuration/nop/engine[@engineType] or check for missing assemblies.");
  8. if (!typeof(IEngine).IsAssignableFrom(engineType))
  9. throw new ConfigurationErrorsException("The type '" + engineType + "' doesn't implement 'Nop.Core.Infrastructure.IEngine' and cannot be configured in /configuration/nop/engine[@engineType] for that purpose.");
  10. return Activator.CreateInstance(engineType) as IEngine;
  11. }
  12. return new NopEngine();
  13. }

从上面可以看到Initialize返回一个IEngine的实例,并调用其方法Initialize。创建IEngine的实例是根据配置文件来获取哪一个IEngine的具体类,如果没有配置这个结点信息或者为空,则返回默认的IEngine的实现NopEngine。

下面我们来看看Nop.Core.Infrastructure.NopEngine里面的核心代码:

 
 
  1. public void Initialize(NopConfig config)
  2. {
  3. //注册依赖
  4. RegisterDependencies(config);
  5. //startup tasks
  6. if (!config.IgnoreStartupTasks)
  7. {
  8. RunStartupTasks();
  9. }
  10. }
  11. /// <summary>
  12. /// 注册依赖
  13. /// </summary>
  14. /// <param name="config">Config</param>
  15. protected virtual void RegisterDependencies(NopConfig config)
  16. {
  17. var builder = new ContainerBuilder();
  18. var container = builder.Build();
  19. //we create new instance of ContainerBuilder
  20. //because Build() or Update() method can only be called once on a ContainerBuilder.
  21. //dependencies
  22. var typeFinder = new WebAppTypeFinder(config);
  23. builder = new ContainerBuilder();
  24. builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
  25. builder.RegisterInstance(this).As<IEngine>().SingleInstance();
  26. builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
  27. builder.Update(container);
  28. //register dependencies provided by other assemblies
  29. builder = new ContainerBuilder();
  30. //查找所有实现了接口IDependencyRegistrar的类
  31. var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
  32. var drInstances = new List<IDependencyRegistrar>();
  33. foreach (var drType in drTypes)
  34. drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
  35. //排序
  36. drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
  37.      //依次调用实现IDependencyRegistrar接口的类的方法Register
  38. foreach (var dependencyRegistrar in drInstances)
  39. dependencyRegistrar.Register(builder, typeFinder);
  40. builder.Update(container);
  41. this._containerManager = new ContainerManager(container);
  42. //set dependency resolver
  43. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
  44. }
  45. 转自蓝狐官网
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值