[Abp 源碼分析]1、Abp 框架啓動流程分析

Abp 不必定僅用於 Asp.Net Core 項目,他也能夠在 Console 與 WinFrom 項目當中進行使用,因此關於啓動流程能夠分爲兩種,一種是 Asp.Net Core 項目的啓動流程,另外則是 ConsoleApplication/WinFrom 項目的啓動流程,在這裏我則是經過 Asp.Net Core 項目的啓動流程來分析,可是他們的核心都是 AbpBootstrapper 這個類。html

本文章基於 Abp 框架的最新版本 v3.7.2git

1、Abp 的入口點

1.1 添加服務與啓用中間件

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

1.2 配置服務

以後來到 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);
}

1.2.1 注入 AbpBootstrapper

AddAbpBootstrapper() 方法內部將使用 AbpBootstrapperCreate 方法建立一個新的 AbpBootstrapper 實例。而且經過 IServiceCollection 將其注入到 Ioc 容器當中。緩存

1.2.2 配置 AspNetCore 相關參數

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

1.2.3 替換 Ioc 容器

最後一句話即:框架

return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);

就是替換掉了 Asp.Net Core 默認的 Ioc 容器,不是 IServiceCollection 了,而是 CastleWindsor 的 IocContainer

1.3 啓用服務

StartupConfigure 方法當中咱們使用了 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 的銷燬方法。

2、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>().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 這個是用於註冊事件總線相關類型的,後面再講。

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 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 裏面。

你可能會有疑問,已經有了模塊的類型,爲何還要一層包裝。

由於爲了確保模塊按正確的順序來進行加載,因此須要擁有每一個模塊的詳細信息,主要是依賴信息,正確的順序應該是核心模塊在最裏層,而啓動模塊應該是在最底層的。因此在後面他還調用了 AbpModuleManagerEnsureKernelModuleToBeFirst() 方法與 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() 的時候與 IApplicationLifetimeApplicationStopping 綁定的。

3、結束語

本篇文章主要將了 ABP 框架的一個基本啓動流程,很簡單並不深刻,後續會繼續發文,由於以前看的是 HK Zhang 的文章,可是他是基於很早以前的版本,在工做中也常常針對 Abp 源碼進行一些擴展和更改,因此想寫一些這方面的文章,後續也會在分析當中貼上具體應用 Abp 框架時候的坑。

4、點此跳轉到總目錄

相關文章
相關標籤/搜索