Abp 不必定仅用于 Asp.Net Core 项目,他也能够在 Console 与 WinFrom 项目当中进行使用,因此关于启动流程能够分为两种,一种是 Asp.Net Core 项目的启动流程,另外则是 ConsoleApplication/WinFrom 项目的启动流程,在这里我则是经过 Asp.Net Core 项目的启动流程来分析,可是他们的核心都是 AbpBootstrapper 这个类。html
本文章基于 Abp 框架的最新版本 v3.7.2 。git
要在 Asp.Net Core 项目当中使用 Abp 框架的话,第一步固然是先添加 Abp.AspNetCore
库啦,以后在咱们 Startup
类的 ConfigureAbpService(IServiceCollection services)
方法里面使用 AddAbp<TStartupModule>
。好比像这样:github
public IServiceProvider ConfigureServices(IServiceCollection services) { return services.AddAbp<HKAbpDemoHostModule>(); }
注意,这里咱们 ConfigureService 返回类型变成了 IServiceProvider
,这是由于在 AddAbp
方法内部替换了 Ioc 容器,变成了 CastleWindsor,后面会接着分析的。shell
而后咱们的 Configure(IApplicationBuilder app, IHostingEnvironment env)
方法里面也会有以下代码:json
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseAbp(); }
以后来到 AddAbp 方法内部,文件目录位置以下:bootstrap
Abp\src\Abp.AspNetCore\AspNetCore\AbpServiceCollectionExtensions.cs
public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null) where TStartupModule : AbpModule { var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction); ConfigureAspNetCore(services, abpBootstrapper.IocManager); return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services); }
在 AddAbpBootstrapper()
方法内部将使用 AbpBootstrapper
的 Create
方法建立一个新的 AbpBootstrapper
实例。而且经过 IServiceCollection
将其注入到 Ioc 容器当中。缓存
private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver) { //See https://github.com/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, AbpAutoValidateAntiforgeryTokenAuthorizationFilter>()); 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 相关的一些配置,好比替换一些默认的服务呀这些。这里重点注意一下这段代码:mvc
mvcOptions.AddAbp(services);
这是 Abp 所写的一个静态方法,这里面就是添加 Abp 内部所实现的过滤器的:app
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()); } }
最后一句话即:框架
return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
就是替换掉了 Asp.Net Core 默认的 Ioc 容器,不是 IServiceCollection
了,而是 CastleWindsor 的 IocContainer
。
在 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 框架启动以后的初始化操做都存放在 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; } }
基础设施的注入是经过 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>().LifestyleSingleton(), Component.For<INotificationConfiguration, NotificationConfiguration>().ImplementedBy<NotificationConfiguration>().LifestyleSingleton(), Component.For<IEmbeddedResourcesConfiguration, EmbeddedResourcesConfiguration>().ImplementedBy<EmbeddedResourcesConfiguration>().LifestyleSingleton(), Component.For<IAbpStartupConfiguration, AbpStartupConfiguration>().ImplementedBy<AbpStartupConfiguration>().LifestyleSingleton(), Component.For<IEntityHistoryConfiguration, 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
这个是用于注册事件总线相关类型的,后面再讲。
_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 Abp modules..."); 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
配置正确的依赖关系。
全部模块的依赖关系与实例都已经被存放到了 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 框架的一个基本启动流程,很简单并不深刻,后续会继续发文,由于以前看的是 HK Zhang 的文章,可是他是基于很早以前的版本,在工做中也常常针对 Abp 源码进行一些扩展和更改,因此想写一些这方面的文章,后续也会在分析当中贴上具体应用 Abp 框架时候的坑。