• 浅谈模块系统与 ABP 框架初始化


    在 ABP 框架当中所有库以及项目都是以模块的形式存在,所有模块都是继承自AbpModule 这个抽象基类,每个模块都拥有四个生命周期。分别是:

    • PreInitialze();
    • Initialize();
    • PostInitialize():
    • ShutDown();

    AddAbp<TStartipModule>()

    在初始化 ABP 框架的时候,通过 services.AddAbp<AbpTestMulitPageWebHostModule>方法将启动模块作为泛型参数传入到 AddAbp 当中。
    之后根据传入的启动模块,初始化 AbpBootstrapper,在 AbpBootstrapper 初始化的时候执行拦截器注册等操作。
    之后配置 Asp Net Core 相关服务,替换控制器、视图组件、过滤器等默认实现,改用ABP 框架的实现,并且将 Ioc 容器替换为 CastleWindsor。

    app.UseAbp()

    之前的 AddAbp 仅仅是在 ConfigureService 注入服务,紧接着就会在 Configure方法启用 Abp 中间件。

    private static void InitializeAbp(IApplicationBuilder app)
    {
        var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
        abpBootstrapper.Initialize();
    }
    

    可以看到在初始化 ABP 的时候,实际上是从 Ioc 容器中解析出 AbpBootStrapper 调用它的初始化方法。

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

    首先注册了日志组件,之后再次注册了 AbpBootStarpper,可能是防止 Ioc 容器没有注册成功吧。
    然后调用了 Castle 的 Install 方法,将一些核心组件通过安装器注入到容器当中。

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

    下一步解析 AbpBootStrapperConfiguration 初始化所有核心模块的配置项。
    之后就是最重要的初始化模块操作了。

    private void LoadAllModules()
    {
        Logger.Debug("Loading Abp modules...");
        List<Type> plugInModuleTypes;
        // 查找所有模块,封装到 List<Type> 容器
        var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();
        Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");
        // 注册模块到 Ioc 容器
        RegisterModules(moduleTypes);
        CreateModules(moduleTypes, plugInModuleTypes);
        _modules.EnsureKernelModuleToBeFirst();
        _modules.EnsureStartupModuleToBeLast();
        SetDependencies();
        Logger.DebugFormat("{0} modules loaded.", _modules.Count);
    }
    

    FindAllModuleTypes

    private List<Type> FindAllModuleTypes(out List<Type> plugInModuleTypes)
    {
        plugInModuleTypes = new List<Type>();
        // 内部根据[DependsOn]特性来,递归获取所有模块
        var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType);
        foreach (var plugInModuleType in _abpPlugInManager.PlugInSources.GetAllModules())
        {
            if (modules.AddIfNotContains(plugInModuleType))
            {
                plugInModuleTypes.Add(plugInModuleType);
            }
        }
        return modules;
    }
    

    CreateModules

    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>();
            // 将模块类型封装到 AbpModule 当中
            var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));
            _modules.Add(moduleInfo);
            // 设置启动模块
            if (moduleType == _modules.StartupModuleType)
            {
                StartupModule = moduleInfo;
            }
            Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
        }
    }
    

    总的来说 CreateModules 的作用就是将之前获取到的模块类型数据再封装为 AbpModuleInfo对象。在 ModuleInfo 对象内部还包括了这个模块所依赖的模块信息。
    构建好所有模块的 ModuleInfo 信息之后,对这个 List<ModuleInfo> 进行排序,将启动模块放在最后,将核心模块放在第一位,具体操作可以参考 _modules.EnsureKernelModuleToBeFirst();_modules.EnsureStartupModuleToBeLast(); 这两个方法。这么做是因为要确保最核心的模块第一位初始化,然后再依次初始化他的子模块。因为是启动模块,所以他是这个依赖树的最低端,留在最后初始化。

    SetDependencies

    遍历 List<ModuleType> 设置每个模块的依赖模块。回到最开始的地方,这里仅仅是初始化模块,之后调用了 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());
    }
    

    启动模块的时候,先按照依赖项来排序,顺序是 Kernal->Module1->Module->2->StartModule。之后从 PreInitialize->Initialize->PostInitialize 这样遍历执行。
    执行完之后所有模块就已经初始化完成了。
    这里可以看到并没有 ShutDown 方法执行,ShutDown 执行的时机是在 AbpBootStrapper 被释放的时候,进行调用。

    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 方法的时候,会将模块列表反转,按照 Start->Module2->Module1->Kernal 这样来关闭。
    模块是 ABP 框架的基础单元,在 ABP 的实现当中模块大部分被当做功能库的形式存在。如果你要使用 ABP 框架的话,必须要定义一个启动模块,不然其他功能是无法正常进行初始化的。

    AbpModule

    public abstract class AbpModule
    {
        /// <summary>
        /// Gets a reference to the IOC manager.
        /// </summary>
        protected internal IIocManager IocManager { get; internal set; }
        /// <summary>
        /// Gets a reference to the ABP configuration.
        /// </summary>
        protected internal IAbpStartupConfiguration Configuration { get; internal set; }
        /// <summary>
        /// Gets or sets the logger.
        /// </summary>
        public ILogger Logger { get; set; }
        protected AbpModule()
        {
            Logger = NullLogger.Instance;
        }
        /// <summary>
        /// This is the first event called on application startup. 
        /// Codes can be placed here to run before dependency injection registrations.
        /// </summary>
        public virtual void PreInitialize()
        {
        }
        /// <summary>
        /// This method is used to register dependencies for this module.
        /// </summary>
        public virtual void Initialize()
        {
        }
        /// <summary>
        /// This method is called lastly on application startup.
        /// </summary>
        public virtual void PostInitialize()
        {
        }
        /// <summary>
        /// This method is called when the application is being shutdown.
        /// </summary>
        public virtual void Shutdown()
        {
        }
        public virtual Assembly[] GetAdditionalAssemblies()
        {
            return new Assembly[0];
        }
        /// <summary>
        /// Checks if given type is an Abp module class.
        /// </summary>
        /// <param name="type">Type to check</param>
        public static bool IsAbpModule(Type type)
        {
            var typeInfo = type.GetTypeInfo();
            return
                typeInfo.IsClass &&
                !typeInfo.IsAbstract &&
                !typeInfo.IsGenericType &&
                typeof(AbpModule).IsAssignableFrom(type);
        }
        /// <summary>
        /// Finds direct depended modules of a module (excluding given module).
        /// </summary>
        public static List<Type> FindDependedModuleTypes(Type moduleType)
        {
            if (!IsAbpModule(moduleType))
            {
                throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
            }
            var list = new List<Type>();
            if (moduleType.GetTypeInfo().IsDefined(typeof(DependsOnAttribute), true))
            {
                var dependsOnAttributes = moduleType.GetTypeInfo().GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();
                foreach (var dependsOnAttribute in dependsOnAttributes)
                {
                    foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes)
                    {
                        list.Add(dependedModuleType);
                    }
                }
            }
            return list;
        }
        public static List<Type> FindDependedModuleTypesRecursivelyIncludingGivenModule(Type moduleType)
        {
            var list = new List<Type>();
            AddModuleAndDependenciesRecursively(list, moduleType);
            list.AddIfNotContains(typeof(AbpKernelModule));
            return list;
        }
        private static void AddModuleAndDependenciesRecursively(List<Type> modules, Type module)
        {
            if (!IsAbpModule(module))
            {
                throw new AbpInitializationException("This type is not an ABP module: " + module.AssemblyQualifiedName);
            }
            if (modules.Contains(module))
            {
                return;
            }
            modules.Add(module);
            var dependedModules = FindDependedModuleTypes(module);
            foreach (var dependedModule in dependedModules)
            {
                AddModuleAndDependenciesRecursively(modules, dependedModule);
            }
        }
    }
    

    在 Abp 模块当中会为你注入一些必须的设施,比如 Ioc 容器,模块配置集合,日志记录器等。
    如果想知道模块如何编写,可以参考 ABP 原有的功能模块实现。

  • 相关阅读:
    Windows Media Player Audio normalize wmp音量规格化
    IE6、IE7、IE8不支持XHTML,不过没关系
    w3.org出现HTML语法错误
    主板bios修改、刷新
    HTML原则:内容放在HTML中,不要依赖CSS
    textarea应使用cols和rows来控制width和height,而不应只使用css
    sata AHCI驱动下载(AMD Intel Nvidia)
    咬文嚼字:中国文字、中国话
    详解W3C标准:html 4.01中的lang属性——实际上它是一个刮胡刀
    热烈欢呼:cnblogs.com博客园首页通过W3C验证
  • 原文地址:https://www.cnblogs.com/myzony/p/8434174.html
Copyright © 2020-2023  润新知