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框架启动流程简要进行了描述,还有很多细节问题没有讲清楚,后面会把这些内容拆分开来说明。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值