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();
}
posted @ 2019-01-07 16:44  KotobukiTsumugi  阅读(1745)  评论(4编辑  收藏  举报