• 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();
    }
    
  • 相关阅读:
    【干货分享】嵌入式学习路线公开!(书籍推荐+视频推荐+练手项目)
    test
    pytest学习小结
    pytest运行报错 TypeError: attrib() got an unexpected keyword argument 'convert'
    pytest插件下载网址
    python修改文件内容的3种方法详解
    PermissionError: [Errno 13] Permission denied 如何解决
    Pycharm退出pytest模式(run pytest in模式)
    直流电机驱动电路设计-----学习笔记
    2019年全国大学生电子设计竞赛赛题分享与浅析
  • 原文地址:https://www.cnblogs.com/zzqvq/p/10234159.html
Copyright © 2020-2023  润新知