1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > [Abp vNext 源码分析] - 1. 框架启动流程分析

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

时间:2020-03-24 18:11:25

相关推荐

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

一、简要说明

本篇文章主要剖析与讲解 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 注入了诸多 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当中的,这里仅讲解 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

原文地址:/myzony/p/10722480.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。