ABP啟動流程分析


添加服務與注冊中間件

 public IServiceProvider ConfigureServices(IServiceCollection services)
 {
    // Configure Abp and Dependency Injection
    return services.AddAbp<MyStudyWebHostModule>(
    // Configure Log4Net logging
    options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
         f => f.UseAbpLog4Net().WithConfig("log4net.config")
         )
     );
 }

先來看看startup這個類的ConfigureServices方法,注意這個方法的返回值,我們知道使用vs創建的項目 返回值為void,但是使用abp的話 返回值是IServiceProvider ,這是因為這里有個AddAbp()方法,這就是我們的入口點,主要做的就是將ABP集成到Asp.Net Core其返回值就是IServiceProvider,因為ABP有自己的第三方IOC框架(CastleWindsor),所以它接管了.net core自帶的容器,至於為什么,其實在WebHost的Initialize(初始化)方法中做的第一件事就是找到StartUP類,執行ConfigureServices()方法

 private void EnsureApplicationServices()
 {
    if (_applicationServices == null)
    {
      EnsureStartup();
      _applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
    }
 }

 private void EnsureStartup()
 {
    if (_startup != null)
    {
        return;
    }
    _startup = _hostingServiceProvider.GetService<IStartup>();

    if (_startup == null)
    {
      hrow new InvalidOperationException($"No startup configured. Please specify startup via WebHostBuilder.UseStartup, WebHostBuilder.Configure, injecting {nameof(IStartup)} or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
    }
}

這里的 _hostingServiceProvider(IServiceProvider), _applicationServiceCollection(IServiceCollection) ,其實是WebHostBuilder在創建WebHost時通過ctor傳遞給webhost的,以后也就是我們程序的根容器,以后每次有請求過來時,我們的根容器都會創建出一個子容器,並交給我們的HttpContext對象
(AutoRequestServicesStartupFilter(StartupFilter類型)會在startup類的Configure方法執行前執行,注冊我們的RequestServicesContainerMiddleware中間件,該中間件會把子容器交給我們的HttpContext對象,實現了該子容器線程內唯一,這里不再展開了,有興趣的可以搜下Asp.net Core DI原理)
好了,不小心扯遠了.回到正題.
startup類中還有個Configure方法,注冊中間件.

app.UseAbp(options => { options.UseAbpRequestLocalization = false; })

添加服務

來到AddAbp方法內部,AddAbpBootstrapper內部其實是調用了Create方法,

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);
}

private static AbpBootstrapper AddAbpBootstrapper<TStartupModule>(IServiceCollection services, Action<AbpBootstrapperOptions> optionsAction)
where TStartupModule : AbpModule
{
  var abpBootstrapper = AbpBootstrapper.Create<TStartupModule>(optionsAction);
  services.AddSingleton(abpBootstrapper);
  return abpBootstrapper;
}

可以看到AddAbpBootstrapper方法就是創建了AbpBootstrapper 並且以單例的形式注冊到我們的ioc根容器
在來看看ConfigureAspNetCore方法

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 AbpMvcContractResolver(iocResolver)
                {
                    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); 內部執行AddFilters方法添加abp自己的過濾器

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));
}

然后在看看WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
里面注冊了一堆ioc相關的服務並創建實現了IServiceProvider的實例類型,接管Asp.net core默認的ServerCollection.

注冊中間件

我們再來看看Configure中的UseABP方法,來到其內部

            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);主要是從Ioc容器中獲取之前單例注冊的abpBootstrapper並執行其初始化方法,並且還獲取了一個生命周期對象,並注冊了一個事件,當程序停止的時候執行我們abpBootstrapperDispose方法

        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());
        }

在來看看abpBootstrapperInitialize初始化方法

        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;
            }
        }

框架啟動之后的初始化操作都存放在 AbpBootstrapper 當中,包括框架內部的各種基礎設施的注入與所有模塊加載操作

框架初始化

注入基礎設施

可以看到上述代碼中 IocManager.IocContainer.Install(new 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()
                );
        }
    }

可以看到有工作單元,緩存,審計日志....等一系列的基礎設施,都是在這里被注冊的.

模塊初始化

加載模塊

_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);

通過AbpModuleManagerInitialize方法加載所有的模塊

public virtual void Initialize(Type startupModule)
{
  _modules = new AbpModuleCollection(startupModule);
   LoadAllModules();
}

可以看到,直接初始化了AbpModuleCollection集合,它本質就是個集合,只不過有些“自定義”的排序方法

  • EnsureStartupModuleToBeLast 確保啟動模塊是最后一個
  • EnsureKernelModuleToBeFirst 確保最核心的模塊是第一個
    下面的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 容器內部

 public static bool RegisterIfNot(this IIocRegistrar iocRegistrar, Type type, DependencyLifeStyle lifeStyle=DependencyLifeStyle.Singleton)
        {
            if (iocRegistrar.IsRegistered(type))
            {
                return false;
            }

            iocRegistrar.Register(type, lifeStyle);
            return true;
        }

CreateModules方法則是從ioc容器中獲取一個模塊,為模塊配置一些屬性如:IocManager以及Configuration 並包裝成AbpModuleInfo對象

private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes)
{
            foreach (var moduleType in moduleTypes)
            {
                var moduleObject = _iocManager.Resolve(moduleType) as AbpModule;
                if (moduleObject == null)
                {
                    throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
                }

                moduleObject.IocManager = _iocManager;
                moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();

                var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));

                _modules.Add(moduleInfo);

                if (moduleType == _modules.StartupModuleType)
                {
                    StartupModule = moduleInfo;
                }

                Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
            }
}
  • 既然有了模塊的類型,為什么還要一層包裝?
  • 因為為了確保模塊按正確的順序來進行加載,所以需要擁有每個模塊的詳細信息,主要是依賴信息,正確的順序應該是核心模塊在最里層,而啟動模塊應該是在最底層的。所以還調用了AbpModuleManagerEnsureKernelModuleToBeFirst方法與EnsureStartupModuleToBeLast方法,以確保正確的加載順序
    SetDependencies方法則是來為每一個AbpModuleInfo配置正確的依賴關系。
初始化模塊

所有模塊的依賴關系與實例都已經被存放到了AbpModuleCollection里面了,下面就來啟動這些模塊了,啟動模塊的方法則是AbpBootstrapper.StartModules
ps:代碼上面貼過

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());
}
/// <summary>
/// Sorts modules according to dependencies.
/// If module A depends on module B, A comes after B in the returned List.
/// </summary>
/// <returns>Sorted list</returns>
public List<AbpModuleInfo> GetSortedModuleListByDependency()
{
    var sortedModules = this.SortByDependencies(x => x.Dependencies);
    EnsureKernelModuleToBeFirst(sortedModules);
    EnsureStartupModuleToBeLast(sortedModules, StartupModuleType);
    return sortedModules;
}

可以看到StartModules中首先執行了GetSortedModuleListByDependency方法 該方法是對模塊進行最后一次排序,確保加載順序正確.排序后,則是依次調用模塊生命周期方法。

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.");
}

其實可以看到這里沒有調用ShutDown方法是因為這個方法只有當程序結束的時候才會調用,他被單獨包裝到了ShutdownModules方法中
ShutdownModules則是app.UseAbp的時候,執行InitializeAbp方法時,把abpBootstrapperIApplicationLifetime的ApplicationStopping進行綁定事件,釋放的時候會執行ShutdownModules

var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
/// <summary>
/// Disposes the ABP system.
/// </summary>
public virtual void Dispose()
{
    if (IsDisposed)
    {
        return;
    }
    IsDisposed = true;
    _moduleManager?.ShutdownModules();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM