本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让你们了解整个 Abp vNext 框架是如何运做的。总的来讲 ,Abp vNext 比起 ABP 框架更加精简。由于在 vNext 版本当中,原来归属于 Abp 库的许多内置的基本组件 (组织单元、拦截器等) 被拆分红了单独的模块,这样咱们来看它整个启动流程就更加地直观清晰。html
要分析其源码,我这里是从他官方的 Demo 模板入手的,你能够在 https://abp.io 上构建你本身的模板项目。工具上我使用的是 Jetbrains 家的 Rider,配置好符号服务器(External Symbols Server),咱们就可以直接调试其底层源码。(由于 Abp vNext 项目使用了 Source Link)服务器
这里我选择的项目是 Web API,直接来到其 Startup.cs
文件,咱们就能够看到在 Startup
类当中的 Configure()
与 ConfigureService()
方法内部咱们注入并启用了 Abp vNext 框架。app
public class Startup { public IServiceProvider ConfigureServices(IServiceCollection services) { // 注入 Abp 相关的服务。 services.AddApplication<DemoAppModule>(options => { options.UseAutofac(); }); // 接管自带的 IoC Container。 return services.BuildServiceProviderFromFactory(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // 配置 ASP.NET Core Mvc 相关参数。 app.InitializeApplication(); } }
在上面咱们能够看到,ABP vNext 在注入服务的时候支持传入一个 Action<AbpApplicationCreationOptions>
委托。上述代码中,这个委托内部使用了 UseAutoFac()
将 AutoFac 的容器注入到了 MS IoC 当中,关于这块代码下文会着重讲解。框架
在上一节看到的服务注册代码,是经过扩展 IServiceCollection
接口编写的一个扩展方法实现的,在方法内部是经过 AbpApplicationFactory
静态工厂来建立一个 AbpApplicationBase
实例。ide
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
对象把本身注入到了服务集合当中。ui
internal class AbpApplicationWithExternalServiceProvider : AbpApplicationBase, IAbpApplicationWithExternalServiceProvider { public AbpApplicationWithExternalServiceProvider( [NotNull] Type startupModuleType, [NotNull] IServiceCollection services, [CanBeNull] Action<AbpApplicationCreationOptions> optionsAction ) : base( startupModuleType, services, optionsAction) { // 注入本身到 IoC 当中。 services.AddSingleton<IAbpApplicationWithExternalServiceProvider>(this); } // 执行框架初始化操做,主要工做是加载模块并执行其初始化方法。 public void Initialize(IServiceProvider serviceProvider) { Check.NotNull(serviceProvider, nameof(serviceProvider)); SetServiceProvider(serviceProvider); InitializeModules(); } }
重点代码在于它的基类构造函数,在基类构造函数当中 Abp vNext 注入了诸多 ASP.NET Core 须要的日志服务、本地化服务等。而且它也抽象出了一个 IModuleLoader
,用于辅助咱们加载模块。this
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(); // 添加核心的 Abp 服务,主要是模块系统相关组件。 services.AddCoreAbpServices(this, options); // 加载模块,并按照依赖关系排序,依次执行他们的生命周期方法。 Modules = LoadModules(services, options); }
提示:
这里的对象访问器其实就是一个占位的类型对象,这样方面后面替换其具体实现。例如在上文当中的
IServiceProvider
经过ObjectAccessor<T>
对象包裹起来,其值是 NULL,可是在后面咱们能够根据本身的须要替换其具体的 Value 。
再回到以前调用 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; } // 经过反射调用 IServiceProvider 的构建方法。 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); }
这里针对 IApplicationBuilder
的扩展是在模块包 Volo.Abp.AspNetCore
当中的,这里仅讲解 ASP.NET Core Mvc 项目是如何处理的。
public static void InitializeApplication([NotNull] this IApplicationBuilder app) { Check.NotNull(app, nameof(app)); // 获取 IApplicationBuilde 的对象访问器,并将其值设置为 app。 app.ApplicationServices.GetRequiredService<ObjectAccessor<IApplicationBuilder>>().Value = app; // 得到以前在 ConfigureService 注册的 Provider 类型,并调用其初始化方法。 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
。