[Abp源码分析]⼀、Abp框架启动流程分析
Abp 不⼀定仅⽤于 Asp.Net Core 项⽬,他也可以在 Console 与 WinFrom 项⽬当中进⾏使⽤,所以关于启动流程可以分为两种,⼀种是 Asp.Net Core 项⽬的启动流程,另外则是 ConsoleApplication/WinFrom 项⽬的启动流程,在这⾥我则是通过 Asp.Net Core 项⽬的启动流程来分析,但是他们的核⼼都是 AbpBootstrapper 这个类。
本⽂章基于 Abp 框架的最新版本。
⼀、Abp 的⼊⼝点
1.1 添加服务与启⽤中间件
要在 Asp.Net Core 项⽬当中使⽤ Abp 框架的话,第⼀步当然是先添加 Abp.AspNetCore 库啦,之后在我们 Startup 类的 ConfigureAbpService(IServiceCollection services) ⽅法⾥⾯使⽤ AddAbp<TStartupModule>。⽐如像这样:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
return services.AddAbp<HKAbpDemoHostModule>();
}
注意,这⾥我们 ConfigureService 返回类型变成了 IServiceProvider ,这是因为在 AddAbp ⽅法内部替换了 Ioc 容器,变成了 CastleWindsor,后⾯会接着分析的。
然后我们的 Configure(IApplicationBuilder app, IHostingEnvironment env) ⽅法⾥⾯也会有如下代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAbp();
}validation框架
1.2 配置服务
之后来到 AddAbp ⽅法内部,⽂件⽬录位置如下:
Abp\src\Abp.AspNetCore\AspNetCore\AbpServiceCollectionExtensions.cs
public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsActi on = null)
where TStartupModule : AbpModule
{
var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);
ConfigureAspNetCore(services, abpBootstrapper.IocManager);
return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
}
1.2.1 注⼊ AbpBootstrapper
在 AddAbpBootstrapper() ⽅法内部将使⽤ AbpBootstrapper 的 Create ⽅法创建⼀个新的 AbpBootstrapper 实例。并且通过 IServiceCollection 将其注⼊到 Ioc 容器当中。
1.2.2 配置 AspNetCore 相关参数
private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver)
{
//See github/aspnet/Mvc/issues/3936 to know why we added these services.
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
//Use DI to create controllers
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
//Use DI to create view components
services.Replace(ServiceDescriptor.Singleton<IViewComponentActivator, ServiceBasedViewComponentActivator>());
//Change anti forgery filters (to work proper with non-browser clients)
services.Replace(ServiceDescriptor.Transient<AutoValidateAntiforgeryTokenAuthorizationFilter, AbpAutoValidateAntiforgeryTokenAuthorizationFilt er>());
services.Replace(ServiceDescriptor.Transient<ValidateAntiforgeryTokenAuthorizationFilter, AbpValidateAntiforgeryTokenAuthorizationFilter>());
//Add feature providers
var partManager = services.GetSingletonServiceOrNull<ApplicationPartManager>();
partManager?.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(iocResolver));
//Configure JSON serializer
services.Configure<MvcJsonOptions>(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new AbpContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
//Configure MVC
services.Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(services);
});
//Configure Razor
services.Insert(0,
ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>(
new ConfigureOptions<RazorViewEngineOptions>(
(options) =>
{
options.FileProviders.Add(new EmbeddedResourceViewFileProvider(iocResolver));
}
)
)
);
}
其⽅法内部做了⽐较多的⼯作,主要是配置与 Asp.Net Core 相关的⼀些配置,⽐如替换⼀些默认的服务呀这些。这⾥重点注意⼀下这段代码:mvcOptions.AddAbp(services);
这是 Abp 所写的⼀个静态⽅法,这⾥⾯就是添加 Abp 内部所实现的过滤器的:
internal static class AbpMvcOptionsExtensions
{
public static void AddAbp(this MvcOptions options, IServiceCollection services)
{
AddConventions(options, services);
AddFilters(options);
AddModelBinders(options);
}
private static void AddConventions(MvcOptions options, IServiceCollection services)
{
options.Conventions.Add(new AbpAppServiceConvention(services));
}
private static void AddFilters(MvcOptions options)
{
options.Filters.AddService(typeof(AbpAuthorizationFilter));
options.Filters.AddService(typeof(AbpAuditActionFilter));
options.Filters.AddService(typeof(AbpValidationActionFilter));
options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter));
options.Filters.AddService(typeof(AbpResultFilter));
}
private static void AddModelBinders(MvcOptions options)
{
options.ModelBinderProviders.Insert(0, new AbpDateTimeModelBinderProvider());
}
}
1.2.3 替换 Ioc 容器
最后⼀句话即:
return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
就是替换掉了 Asp.Net Core 默认的 Ioc 容器,不是 IServiceCollection 了,⽽是 CastleWindsor 的 IocContainer。
1.3 启⽤服务
在 Startup 的 Configure ⽅法当中我们使⽤了 app.UseAbp() 来启⽤ Abp 框架,他的定义可以在以下位置到:
Abp\src\Abp.AspNetCore\AspNetCore\AbpApplicationBuilderExtensions.cs
public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction)
{
Check.NotNull(app, nameof(app));
var options = new AbpApplicationBuilderOptions();
optionsAction?.Invoke(options);
if (options.UseCastleLoggerFactory)
{
app.UseCastleLoggerFactory();
}
InitializeAbp(app);
if (options.UseAbpRequestLocalization)
{
//TODO: This should be added later than authorization middleware!
app.UseAbpRequestLocalization();
}
if (options.UseSecurityHeaders)
{
app.UseAbpSecurityHeaders();
}
}
它可以允许⽤户⾃⼰配置⼀些相关的参数,并且在 InitializeAbp(app) ⾥⾯进⾏了初始化操作。
跳转到 InitializeAbp(app) 定义的地⽅:
private static void InitializeAbp(IApplicationBuilder app)
{
var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
abpBootstrapper.Initialize();
var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
}
这⾥通过 IServiceProvider 获取到之前 AddAbp 注⼊的 AbpBootstrapper 对象,并且调⽤其初始化⽅法。
这⾥还注册了⼀个⽣命周期事件,当程序停⽌的时候调⽤ AbpBootstrapper 的销毁⽅法。
⼆、Abp 框架初始化
整个 Abp 框架启动之后的初始化操作都存放在 AbpBootstrapper 当中,包括框架内部的各种基础设施的注⼊与所有模块加载操作,在上⽂可以看到是调⽤的 Initialize() ⽅法来进⾏初始化。
public virtual void Initialize()
{
ResolveLogger();
try
{
RegisterBootstrapper();
IocManager.IocContainer.Install(new AbpCoreInstaller());
IocManager.Resolve<AbpPlugInManager>().PlugInSources.AddRange(PlugInSources);
IocManager.Resolve<AbpStartupConfiguration>().Initialize();
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
_moduleManager.StartModules();
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString(), ex);
throw;
}
}
1.1 注⼊基础设施
基础设施的注⼊是通过 Windsor 的 IocContainer 来注册所有基础设施的,可以看到他使⽤ Install() ⽅法来注册。我们可以看⼀下 AbpCoreInstaller 的定义。
internal class AbpCoreInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IUnitOfWorkDefaultOptions, UnitOfWorkDefaultOptions>().ImplementedBy<UnitOfWorkDefaultOptions>().LifestyleSingleton(), Component.For<INavigationConfiguration, NavigationConfiguration>().ImplementedBy<NavigationConfiguration>().LifestyleSingleton(),
Component.For<ILocalizationConfiguration, LocalizationConfiguration>().ImplementedBy<LocalizationConfiguration>().LifestyleSingleton(), Component.For<IAuthorizationConfiguration, AuthorizationConfiguration>().ImplementedBy<AuthorizationConfiguration>().LifestyleSingleton(), Component.For<IValidationConfiguration, ValidationConfiguration>().ImplementedBy<ValidationConfiguration>().LifestyleSingleton(),
Component.For<IFeatureConfiguration, FeatureConfiguration>().ImplementedBy<FeatureConfiguration>().LifestyleSingleton(),
Component.For<ISettingsConfiguration, SettingsConfiguration>().ImplementedBy<SettingsConfiguration>().LifestyleSingleton(),
Component.For<IModuleConfigurations, ModuleConfigurations>().ImplementedBy<ModuleConfigurations>().LifestyleSingleton(),
Component.For<IEventBusConfiguration, EventBusConfiguration>().ImplementedBy<EventBusConfiguration>().LifestyleSingleton(),
Component.For<IMultiTenancyConfig, MultiTenancyConfig>().ImplementedBy<MultiTenancyConfig>().LifestyleSingleton(),
Component.For<ICachingConfiguration, CachingConfiguration>().ImplementedBy<CachingConfiguration>().LifestyleSingleton(),
Component.For<IAuditingConfiguration, AuditingConfiguration>().ImplementedBy<AuditingConfiguration>().LifestyleSingleton(),
Component.For<IBackgroundJobConfiguration, BackgroundJobConfiguration>().ImplementedBy<BackgroundJobConfiguration>().LifestyleSinglet on(),
Component.For<INotificationConfiguration, NotificationConfiguration>().ImplementedBy<NotificationConfiguration>().LifestyleSingleton(),
Component.For<IEmbeddedResourcesConfiguration, EmbeddedResourcesConfiguration>().ImplementedBy<EmbeddedResourcesConfiguration >().LifestyleSingleton(),
Component.For<IAbpStartupConfiguration, AbpStartupConfiguration>().ImplementedBy<AbpStartupConfiguration>().LifestyleSingleton(), Component.For<IEntityHistoryC
onfiguration, EntityHistoryConfiguration>().ImplementedBy<EntityHistoryConfiguration>().LifestyleSingleton(), Component.For<ITypeFinder, TypeFinder>().ImplementedBy<TypeFinder>().LifestyleSingleton(),
Component.For<IAbpPlugInManager, AbpPlugInManager>().ImplementedBy<AbpPlugInManager>().LifestyleSingleton(),
Component.For<IAbpModuleManager, AbpModuleManager>().ImplementedBy<AbpModuleManager>().LifestyleSingleton(),
Component.For<IAssemblyFinder, AbpAssemblyFinder>().ImplementedBy<AbpAssemblyFinder>().LifestyleSingleton(),
Component.For<ILocalizationManager, LocalizationManager>().ImplementedBy<LocalizationManager>().LifestyleSingleton()
);
}
}
可以看到他注⼊了很多配置项,⽐如说缓存,权限配置,还有模块管理器之类的,这些我会在以后的⽂章当中进⾏具体解释。
他继承了 IWindsorInstaller 接⼝,这个是 CastleWindsor 所提供的,专门⽤于某⼀些功能的类型进⾏统⼀注册,除了 AbpCoreInstaller 其实还有 EventBusInstaller 这个是⽤于注册事件总线相关类型的,后⾯再讲。
1.2 模块初始化
1.2.1 加载模块
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
通过 ModuleManager.Initialize() 来加载所有模块。
public virtual void Initialize(Type startupModule)
{
_modules = new AbpModuleCollection(startupModule);
LoadAllModules();
}
他的内部⾸先初始化了⼀个集合,这是 Abp ⾃⼰定义的,它的本质就是⼀个集合,只不过提供了⼀些诸如根据依赖关系来排序的操作,下⾯的 LoadAllModules() 则是真正的加载模块了。
private void LoadAllModules()
{
Logger.Debug("Loading ");
List<Type> plugInModuleTypes;
var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();
Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");
RegisterModules(moduleTypes);
CreateModules(moduleTypes, plugInModuleTypes);
_modules.EnsureKernelModuleToBeFirst();
_modules.EnsureStartupModuleToBeLast();
SetDependencies();
Logger.DebugFormat("{0} modules loaded.", _modules.Count);
}
这⾥很简单了,⾸先在 FindAllModuleTypes() ⽅法内部通过启动模块上⾯的 [DependsOn] 标签来从最外层加载插件形式的模块与内部模块。
之后将通过 RegisterModules 所有模块单例注⼊到 Ioc 容器内部,⽽ CreateModules() ⽅法则为每个模块来配置⾥⾯的⼀些公有属性,并且将其包装到 AbpModuleInfo ⾥⾯。
你可能会有疑问,已经有了模块的类型,为什么还要⼀层包装。
因为为了确保模块按正确的顺序来进⾏加载,所以需要拥有每个模块的详细信息,主要是依赖信息,
正确的顺序应该是核⼼模块在最⾥层,⽽启动模块应该是在最底层的。所以在后⾯他还调⽤了 AbpModuleManager 的 EnsureKernelModuleToBeFirst() ⽅法与 EnsureStartupModuleToBeLast() ⽅法,以确保正确的加载顺序。
⽽ SetDependencies() ⽅法则是来为每⼀个 ModuleInfo 配置正确的依赖关系。
1.2.2 初始化模块
所有模块的依赖关系与实例都已经被存放到了 AbpModuleCollection ⾥⾯了,下⾯就来启动这些模块了,启动模块的⽅法则是 StartModules()。
public virtual void StartModules()
{
var sortedModules = _modules.GetSortedModuleListByDependency();
sortedModules.ForEach(module => module.Instance.PreInitialize());
sortedModules.ForEach(module => module.Instance.Initialize());
sortedModules.ForEach(module => module.Instance.PostInitialize());
}
可以看到这⾥的 GetSortedModuleListByDependency() ⽅法就是根据依赖关系来进⾏最后的排序,以确保模块加载顺序的正确。
后⾯则没什么了,使⽤ ForEach 来按照正常的⽣命周期来调⽤所有模块的⼏个⽣命周期⽅法。
可以看到这⾥没有调⽤ ShutDown() ⽅法是因为这个⽅法只有当程序结束的时候才会调⽤,他被单独包装到了⼀个⽅法当中。
public virtual void ShutdownModules()
{
Logger.Debug("Shutting down has been started");
var sortedModules = _modules.GetSortedModuleListByDependency();
sortedModules.Reverse();
sortedModules.ForEach(sm => sm.Instance.Shutdown());
Logger.Debug("Shutting down completed.");
}
⽽ ShutdownModules() 则是在我们的 AbpBootStrapper 的 Dispose 时候才被调⽤,他什么时候被销毁的呢?就是我们最开始 app.UseAbp() 的时候与 IApplicationLifetime 的ApplicationStopping 绑定的。
三、结束语
本篇⽂章主要将了 ABP 框架的⼀个基本启动流程,很简单并不深⼊,后续会继续发⽂,因为之前看的是 的⽂章,但是他是基于很早之前的版本,在⼯作中也经常针对 Abp 源码进⾏⼀些扩展和更改,所以想写⼀些这⽅⾯的⽂章,后续也会在分析当中贴上具体应⽤ Abp 框架时候的坑。
四、
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论