ABP學習實踐(十一)--框架啓動流程

在經過前面的實踐後,利用ABP框架解決簡單的業務需求(增刪改查)基本是沒問題了。然而ABP框架的能力可不止這些,想要更好的使用那些高級特性,就需要了解下ABP框架的結構和工作原理了。


1.框架結構

1.1項目依賴關係

在這裏插入圖片描述
再次回顧下系列文章第一篇中所描述的項目依賴關係。應用層Application和基礎設施層EntityFrameworkCore都依賴於領域層Core,而呈現和分佈式應用層Web又同時依賴於應用層Application和基礎設施層EntityFrameworkCore。

1.2類依賴關係

在這裏插入圖片描述
上面是到目前爲止解決方案中類依賴關係圖,看起來挺複雜的,但其實核心的就是紅色方框中的內容。另外由於ABP框架大量用到依賴注入、模塊系統等特性,有些事實上的依賴關係並沒有在圖中體現。

在這裏插入圖片描述
上面這張圖是簡化過的類依賴關係圖,也是解決方案最開始的狀態。可以看到項目啓動過程中幾個關鍵點,Startup啓動類不用多說,數據庫選項配置DbContextOptionConfigurer、Web項目模塊xxxWebModule和其他項目模塊xxxModule等。

2.啓動流程

在這裏插入圖片描述

2.1 Program.cs

Program.cs的用途自然就是整個項目的入口了,項目啓動就就從這裏開始。在Main函數中構建WebHost並啓動。在構建WebHost時以Startup作爲啓動類。這點和原生的AspNetCore項目是一致的。

   public static void Main(string[] args)
   {
       var host = new WebHostBuilder()
           .UseKestrel()
           .UseContentRoot(Directory.GetCurrentDirectory())
           .UseIISIntegration()
           .UseStartup<Startup>()
           .Build();

       host.Run();
   }

2.2 Startup.cs

在Startup中有兩個方法,一個是ConfigureServices,輸入參數類型是IServiceCollection,輸出參數類型爲IServiceProvider。在這個方法中首先是使用擴展方法AddAbpDbContext < TDbCOntext >配置數據庫上下文,最後又使用AddAbp< AbpDemoWebModule >對ABP框架和依賴注入進行配置,同時也將AbpDemoWebModule作爲了啓動模塊。

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //配置數據上下文
        services.AddAbpDbContext<AbpDemoDbContext>(options =>
        {
            DbContextOptionsConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
        });

        services.AddControllersWithViews(options =>
        {
            options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
        }).AddNewtonsoftJson();

        //配置ABP框架及依賴注入
        return services.AddAbp<AbpDemoWebModule>(options =>
        {
            //配置Log4Net日誌
            options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                f => f.UseAbpLog4Net().WithConfig("log4net.config")
            );
        });
    }

先來看看重點的AddAbp< AbpDemoWebModule >是如何實現的。

    public static IServiceProvider AddAbp<TStartupModule>(
      this IServiceCollection services,
      Action<AbpBootstrapperOptions> optionsAction = null)
      where TStartupModule : AbpModule
    {
      //創建AbpBootstrapper實例並注入到容器中
      AbpBootstrapper abpBootstrapper = AbpServiceCollectionExtensions.AddAbpBootstrapper<TStartupModule>(services, optionsAction);
      //配置AspNetCore相關參數,如替換默認服務、添加Abp過濾器等
      AbpServiceCollectionExtensions.ConfigureAspNetCore(services, (IIocResolver) abpBootstrapper.IocManager);
      //替換容器,將AspNet Core默認的Ioc容器IServiceCollection替換爲CastleWindsor的IocContainer
      return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
    }

Startup中另一個方法是Configure,在這個方法中實現了ABP框架初始化和Web應用的一些常用配置。

   public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
   {
       app.UseAbp(); //初始化ABP框架

       if (env.IsDevelopment())
       {
           app.UseDeveloperExceptionPage();
           app.UseDatabaseErrorPage();
       }
       else
       {
           app.UseExceptionHandler("/Error");
       }

       app.UseStaticFiles();
       app.UseRouting();

       app.UseEndpoints(endpoints =>
       {
           endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
       });
   }

那麼最關鍵的一行代碼app.UseAbp()到底是如何初始化ABP框架的?通過源代碼可以看到有配置項的引入和一堆檢查。

   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);//初始化ABP框架

       if (options.UseAbpRequestLocalization)
       {
           //TODO: This should be added later than authorization middleware!
           app.UseAbpRequestLocalization();
       }

       if (options.UseSecurityHeaders)
       {
           app.UseAbpSecurityHeaders();
       }
   }

核心的一句InitializeAbp()其實就是找到之前的AbpBootstrapper實例初始化。

    private static void InitializeAbp(IApplicationBuilder app)
    {
        var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
        abpBootstrapper.Initialize();//ABP框架初始化

        var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
        applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
    }

而AbpBootstrapper實例的Initialize()方法纔是真正開始ABP框架的初始化。

    public virtual void Initialize()
    {        
        //日誌
        ResolveLogger();
        try
        {
            //註冊Bootstrapper
            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;
        }
    }

其中比較關鍵的是模塊的初始化和啓動。按照ABP框架的模塊系統,不同功能域之間以模塊的形式相互依賴。在模塊的初始化和啓動階段,框架從AbpDemoWebModule模塊類開始,不斷循環查找直到遍歷完成所有Module,之後將所有Module按依賴關係進行排序,先後執行預初始操作和初始化操作。這個過程自然也包括領域層AbpDemoCoreModule、應用層AbpDemoApplicationModule、基礎設施層AbpDemoEntityFrameworkCoreModule。

3.小結

經過上面的過程,ABP框架從基礎設施、各個模塊、各項配置都初始化並配置完成,整個項目也順利的啓動起來。不過篇幅有限,只是將ABP框架啓動流程簡要進行了描述,還有很多細節問題沒有講清楚,後面會把這些內容拆分開來說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章