一、简要说明

本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的。总的来说 ,Abp vNext 比起 ABP 框架更加精简。因为在 vNext 版本当中,原来归属于 Abp 库的许多内置的基本组件 (组织单元、拦截器等) 被拆分成了单独的模块,这样我们来看它整个启动流程就更加地直观清晰。

二、源码分析

要分析其源码,我这里是从他官方的 Demo 模板入手的,你可以在 https://abp.io 上构建你自己的模板项目。工具上我使用的是 Jetbrains 家的 Rider,配置好符号服务器(External Symbols Server),我们就能够直接调试其底层源码。(因为 Abp vNext 项目使用了 Source Link)

2.1 Startup 文件的入口点

这里我选择的项目是 Web API,直接来到其 Startup.cs 文件,我们就可以看到在 Startup 类当中的 Configure() 与 ConfigureService() 方法内部我们注入并启用了 Abp vNext 框架。

public class Startup{public IServiceProvider ConfigureServices(IServiceCollection services){

        services.AddApplication<DemoAppModule>(options =>                                               {                                                   options.UseAutofac();                                               });

return services.BuildServiceProviderFromFactory();    }

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){

        app.InitializeApplication();    }}

在上面我们可以看到,ABP vNext 在注入服务的时候支持传入一个 Action<AbpApplicationCreationOptions> 委托。上述代码中,这个委托内部使用了 UseAutoFac() 将 AutoFac 的容器注入到了 MS IoC 当中,关于这块代码下文会着重讲解。

2.2 Abp 服务注册

在上一节看到的服务注册代码,是通过扩展 IServiceCollection 接口编写的一个扩展方法实现的,在方法内部是通过 AbpApplicationFactory 静态工厂来创建一个 AbpApplicationBase 实例。

public static class ServiceCollectionApplicationExtensions{public static IAbpApplicationWithExternalServiceProvider AddApplication<TStartupModule>(        [NotNull] this IServiceCollection services,        [CanBeNull] Action<AbpApplicationCreationOptions> optionsAction = null)where TStartupModule : IAbpModule    {return AbpApplicationFactory.Create<TStartupModule>(services, optionsAction);    }

}

在这个方法当中,通过名字 WithExternalServiceProvider 我们就知道,这个 Applictaion 是依赖于外部的 IServiceProvider 实例。

提示:

它继承的 AbpApplicationBase 基类还拥有另外一个实现,即 AbpApplicationWithInternalServiceProvider 类型,该类型一般 用于控制台程序,它会在 Abp vNext 框架内自行构建一个 IServiceProvider 对象。

我们回到之前的代码,在这个 AbpApplicationWithExternalServiceProvider 类型内部的构造方法很简单,只是通过 IServiceCollection 对象把自己注入到了服务集合当中。

internal class AbpApplicationWithExternalServiceProvider : AbpApplicationBase, IAbpApplicationWithExternalServiceProvider{public AbpApplicationWithExternalServiceProvider(        [NotNull] Type startupModuleType,        [NotNull] IServiceCollection services,        [CanBeNull] Action<AbpApplicationCreationOptions> optionsAction) : base(            startupModuleType,            services,            optionsAction){

        services.AddSingleton<IAbpApplicationWithExternalServiceProvider>(this);    }

public void Initialize(IServiceProvider serviceProvider){        Check.NotNull(serviceProvider, nameof(serviceProvider));

        SetServiceProvider(serviceProvider);

        InitializeModules();    }}

重点代码在于它的基类构造函数,在基类构造函数当中 Abp vNext 注入了诸多 ASP.NET Core 需要的日志服务、本地化服务等。并且它也抽象出了一个 IModuleLoader,用于辅助我们加载模块。

internal AbpApplicationBase(    [NotNull] Type startupModuleType,    [NotNull] IServiceCollection services,    [CanBeNull] Action<AbpApplicationCreationOptions> optionsAction){    Check.NotNull(startupModuleType, nameof(startupModuleType));    Check.NotNull(services, nameof(services));

    StartupModuleType = startupModuleType;    Services = services;

    services.TryAddObjectAccessor<IServiceProvider>();

var options = new AbpApplicationCreationOptions(services);    optionsAction?.Invoke(options);

    services.AddSingleton<IAbpApplication>(this);    services.AddSingleton<IModuleContainer>(this);

    services.AddCoreServices();

    services.AddCoreAbpServices(this, options);

    Modules = LoadModules(services, options);}

提示:

这里的对象访问器其实就是一个占位的类型对象,这样方面后面替换其具体实现。例如在上文当中的 IServiceProvider 通过 ObjectAccessor<T> 对象包裹起来,其值是 NULL,但是在后面我们可以根据自己的需要替换其具体的 Value 。

2.3 替换 IoC 容器

再回到之前调用 AddApplication<T>() 传递的委托方法,在其内部我们调用了 UseAutofac() 方法。这个方法很简单,内部就只有三行代码。

这三行代码主要是初始化了一个 AutoFac 的容器构建对象,其次注入 IServiceProviderFactory 和 Abp 的默认实现 AbpAutofacServiceProviderFactory

public static void UseAutofac(this AbpApplicationCreationOptions options){var builder = new ContainerBuilder();    options.Services.AddObjectAccessor(builder);

    options.Services.AddSingleton((IServiceProviderFactory<ContainerBuilder>) new AbpAutofacServiceProviderFactory(builder));}

这个工厂类的就是在构建 IServiceProvider 的时候使用,即 BuildServiceProviderFromFactory() 方法。该方法内部逻辑很简单,就是从已经注册的服务集合(IServiceCollection)当中获得之前注册的工厂类,通过调用工厂类的 CreateServiceProvider()方法构建 IServiceProvider,并作为返回值替换掉默认的 IoC 容器。

public static IServiceProvider BuildServiceProviderFromFactory([NotNull] this IServiceCollection services){    Check.NotNull(services, nameof(services));

foreach (var service in services)    {var factoryInterface = service.ImplementationInstance?.GetType()            .GetTypeInfo()            .GetInterfaces()            .FirstOrDefault(i => i.GetTypeInfo().IsGenericType &&                                 i.GetGenericTypeDefinition() == typeof(IServiceProviderFactory<>));

if (factoryInterface == null)        {continue;        }

var containerBuilderType = factoryInterface.GenericTypeArguments[0];return (IServiceProvider)typeof(ServiceCollectionCommonExtensions)            .GetTypeInfo()            .GetMethods()            .Single(m => m.Name == nameof(BuildServiceProviderFromFactory) && m.IsGenericMethod)            .MakeGenericMethod(containerBuilderType)            .Invoke(null, new object[] { services, null });    }

return services.BuildServiceProvider();}

public static IServiceProvider BuildServiceProviderFromFactory<TContainerBuilder>([NotNull] this IServiceCollection services, Action<TContainerBuilder> builderAction = null){    Check.NotNull(services, nameof(services));

var serviceProviderFactory = services.GetSingletonInstanceOrNull<IServiceProviderFactory<TContainerBuilder>>();if (serviceProviderFactory == null)    {throw new AbpException($"Could not find {typeof(IServiceProviderFactory<TContainerBuilder>).FullName} in {services}.");    }

var builder = serviceProviderFactory.CreateBuilder(services);    builderAction?.Invoke(builder);return serviceProviderFactory.CreateServiceProvider(builder);}

2.3 初始化 Abp 框架

这里针对 IApplicationBuilder 的扩展是在模块包 Volo.Abp.AspNetCore 当中的,这里仅讲解 ASP.NET Core Mvc 项目是如何处理的。

public static void InitializeApplication([NotNull] this IApplicationBuilder app){    Check.NotNull(app, nameof(app));

    app.ApplicationServices.GetRequiredService<ObjectAccessor<IApplicationBuilder>>().Value = app;

    app.ApplicationServices.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Initialize(app.ApplicationServices);}

这里可能会疑惑 ObjectAccessor<IApplicationBuilder> 是在什么时候注入的,其实该类型是在 AbpAspNetCoreModule 模块注册的。

public class AbpAspNetCoreModule : AbpModule{

public override void ConfigureServices(ServiceConfigurationContext context){

        context.Services.AddObjectAccessor<IApplicationBuilder>();    }

}

接着看初始化方法内部的操作,初始化方法定义是在基类当中,方法名是 InitializeModules() ,在方法内部,通过 IModuleManager 来执行模块的初始化方法。

protected virtual void InitializeModules(){using (var scope = ServiceProvider.CreateScope())    {        scope.ServiceProvider            .GetRequiredService<IModuleManager>()            .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider));    }}

除了模块的初始化,模块的销毁动作 Abp vNext 好像是没有作处理,你可以挂载 IApplicationLifetime.ApplicationStopping 事件来手动执行模块的销毁方法。

三、总结

总体来说 Abp vNext 的启动流程与之前精简了许多,这是因为在新的框架当中将许多基础组件从核心层移除了,用户可以自由选择自己需要加载的组件。IoC 相关的代码则是通过的 Microsoft Dependency 提供的 IServiceProvider/IServiceCollection 进行操作,没有了之前的 IocManager

原文地址:https://www.cnblogs.com/myzony/p/10722480.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

[Abp vNext 源码分析] - 1. 框架启动流程分析相关推荐

  1. ThinkPHP5.0源码学习之框架启动流程

    ThinkPHP5框架的启动流程图如下: ThinkPHP5的启动流程按照文件分为三步: 1.请求入口(public/index.php) 2.框架启动(thinkphp/start.php) 3.应 ...

  2. [Abp vNext 源码分析] - 5. DDD 的领域层支持(仓储、实体、值对象)

    一.简要介绍 ABP vNext 框架本身就是围绕着 DDD 理念进行设计的,所以在 DDD 里面我们能够见到的实体.仓储.值对象.领域服务,ABP vNext 框架都为我们进行了实现,这些基础设施都 ...

  3. 12.源码阅读(app启动流程-android api 26)

    activity的启动流程之前已经通过源码了解了,那么app的启动流程是怎样的,从我们按下app的图标,到应用启动起来显示出画面,中间都经历了什么? 安卓是基于java的,所以和java有一定的相似性 ...

  4. kotlin coroutine源码解析之Job启动流程

    目录 Job启动流程 launch流程分析 父子Job关联分析 结论 Job启动流程 job启动流程,我们先从一段最简单使用协程的代码开始,进行代码跟跟踪,顺便引出几个关键的概念,在后面章节里面去单独 ...

  5. [Abp vNext 源码分析] - 19. 多租户

    一.简介 ABP vNext 原生支持多租户体系,可以让开发人员快速地基于框架开发 SaaS 系统.ABP vNext 实现多租户的思路也非常简单,通过一个 TenantId 来分割各个租户的数据,并 ...

  6. [Abp vNext 源码分析] - 2. 模块系统的变化

    一.简要说明 本篇文章主要分析 Abp vNext 当中的模块系统,从类型构造层面上来看,Abp vNext 当中不再只是单纯的通过 AbpModuleManager 来管理其他的模块,它现在则是 I ...

  7. [Abp vNext 源码分析] - 4. 工作单元

    一.简要说明 统一工作单元是一个比较重要的基础设施组件,它负责管理整个业务流程当中涉及到的数据库事务,一旦某个环节出现异常自动进行回滚处理. 在 ABP vNext 框架当中,工作单元被独立出来作为一 ...

  8. [Abp vNext 源码分析] - 3. 依赖注入与拦截器

    一.简要说明 ABP vNext 框架在使用依赖注入服务的时候,是直接使用的微软提供的 Microsoft.Extensions.DependencyInjection 包.这里与原来的 ABP 框架 ...

  9. [Abp vNext 源码分析] - 18. 单元测试

    简介 ABP vNext 框架使用 xUnit 作为单元测试组件,官方的所有模块都编写了大量的 单元/集成测试 确保功能正常.由于 ABP vNext 模块化系统的原因,开发人员在建立单元测试项目的时 ...

最新文章

  1. windows云服务器价格_免费windows云服务器
  2. Flomaster 2020中文版
  3. 可怕!那些你看不到的进程
  4. Python应用实战-Python爬取4000+股票数据,并用plotly绘制了树状热力图(treemap)
  5. 前端学习(2223):react之jsx的样式和注释(2)
  6. Bootstrap 插件的事件
  7. JavaScript获取距离某天前或后的日期
  8. 洛谷1008 三连击
  9. 过来人谈在美国大学里的中国研究生
  10. python编程是什么东西_编程python是什么
  11. 麻省理工18年春软件构造课程阅读01“静态检查”
  12. git add提示LF will be replaced by CRLF
  13. 定义一个方法用于判断一个字符串是否是对称的字符串(StringBuilder),例如:abcba、上海自来水来自海上均为对称字符串。
  14. 锡兰1.0.0现已上市
  15. Struck: Structured Output Tracking with Kernels
  16. 信用证的好处!只要有信用证,没有不符点,就能收到钱!
  17. 用计算机打根号怎么打,根号在电脑上怎么打出来啊?
  18. 省市区(县)三级联动代码(js 数据源)
  19. SpringBoot整合rabbitmq使用案例
  20. 客户关系管理项目——用户登录模块设计

热门文章

  1. 在c语言中load,一道题理清Objective-C中的load和initialize
  2. (原創) 今天拿到學生證了 (日記)
  3. Tomcat定义虚拟主机案例
  4. hibernate自定义校验器使用(字段在in范围之内)
  5. Facebook用户遭遇千年虫:瞬间有了46年老友
  6. Ansible 一步一步从入门到精通(一)
  7. Centos-启动network报错RTNETLINK answers: File exists解决方法
  8. ActionContext和ActionSupport的学习
  9. 虎年云原生落地技术趋势
  10. 一行代码完成定时任务调度,基于Quartz的UI可视化操作组件 GZY.Quartz.MUI