ABP學習實踐(十二)--模塊系統

模塊Module是ABP框架體系很重要的概念,不同的功能組件包括項目之間都是以模塊的形式進行關聯的。在ABP框架的啓動過程中,模塊的遍歷、初始化、啓動也是很重要的一環。


1.模塊的定義

1.1定義

在ABP框架中定義了基類AbpModule,只要是繼承自AbpModule的類就是模塊。先來看看這個基類的定義。

namespace Abp.Modules
{
    public abstract class AbpModule
    {
        //獲取對IOC管理器的引用
        protected internal IIocManager IocManager { get; internal set; }
        // 獲取對ABP配置項的引用
        protected internal IAbpStartupConfiguration Configuration { get; internal set; }
        // 獲取或設置日誌
        public ILogger Logger { get; set; }

        protected AbpModule()
        {
            Logger = NullLogger.Instance;
        }

        // 預初始化
        public virtual void PreInitialize()
        {
        }

        // 初始化
        public virtual void Initialize()
        {
        }
        
        //初始化後
        public virtual void PostInitialize()
        {

        }

        // 關閉
        public virtual void Shutdown()
        {

        }

        public virtual Assembly[] GetAdditionalAssemblies()
        {
            return new Assembly[0];
        }

        // 檢查是否爲模塊
        public static bool IsAbpModule(Type type)
        {
            var typeInfo = type.GetTypeInfo();
            return
                typeInfo.IsClass &&
                !typeInfo.IsAbstract &&
                !typeInfo.IsGenericType &&
                typeof(AbpModule).IsAssignableFrom(type);
        }

        // 查找依賴模塊
        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);
            }
        }
    }
}

在AbpModule中可以看到其內部以接口形式定義了IoC管理器、模塊配置項和日誌組件,此外還有模塊的生命週期事件和查找當前模塊所依賴模塊的方法。

1.2生命週期

在AbpModule可以看到模塊的四個生命週期事件:

生命週期事件 說明
PreInitialize 預初始化:在初始化之前配置框架和其他模塊。能夠在依賴注入註冊之前,在這個方法中指定需要注入的自定義啓動類
Initialize 初始化:一般是來進行依賴注入的註冊,常通過 IocManager.RegisterAssemblyByConvention 來實現
PostInitialize 初始化後:用來解析依賴關係
Shutdown 關閉:當應用關閉以後被調用

對於任意一個模塊,這四個方法的執行順序依次爲PreInitialize–>Initialize–>PostInitialize–>Shutdown。

2.模塊的依賴

2.1特性

ABP框架提供了DependsOn屬性來顯式說明模塊間的依賴關係。可以看到DependsOn屬性支持的是數組,所以一個模塊可以依賴於多個模塊。

namespace Abp.Modules
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public class DependsOnAttribute : Attribute
    {
        public Type[] DependedModuleTypes { get; private set; }

        public DependsOnAttribute(params Type[] dependedModuleTypes)
        {
            DependedModuleTypes = dependedModuleTypes;
        }
    }
}

再來看看示例解決方案中各模塊的依賴關係。

//Web項目--呈現與分佈式服務層
[DependsOn(
    typeof(AbpDemoApplicationModule), 
    typeof(AbpDemoEntityFrameworkCoreModule), 
    typeof(AbpAspNetCoreModule))]
public class AbpDemoWebModule : AbpModule
{
	//to do
}

//EntityFrameworkCore項目--基礎設施層
[DependsOn(
    typeof(AbpDemoCoreModule), 
    typeof(AbpEntityFrameworkCoreModule))]
public class AbpDemoEntityFrameworkCoreModule : AbpModule
{
	// to do
}

//Application項目--應用層
[DependsOn(
    typeof(AbpDemoCoreModule), 
    typeof(AbpAutoMapperModule))]
public class AbpDemoApplicationModule : AbpModule
{
	// to do
}

//Core項目--領域層
public class AbpDemoCoreModule : AbpModule
{
	// to do
}

3.模塊的啓動

3.1啓動順序

對於每個模塊都用同樣的生命週期事件,但是有多個模塊而且這些模塊互相之間存在依賴關係時,這些生命週期事件又該如何執行?對於這種情況,ABP框架作了清晰的定義:所有模塊執行完PreInitialize預初始化方法後,所有模塊再執行Initialize初始化方法,之後所有模塊再執行PostInitialize初始化後方法。在ABP框架的啓動過程中也遵循這一流程。
現在再回到AbpBootstrapper的Initialize初始化方法中,仔細查看模塊啓動的全過程。

   _moduleManager = IocManager.Resolve<AbpModuleManager>();
   _moduleManager.Initialize(StartupModule);
   _moduleManager.StartModules();
3.1.1 實例化模塊管理器
3.1.2 初始化模塊管理器
 public virtual void Initialize(Type startupModule)
 {
     _modules = new AbpModuleCollection(startupModule);
     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);
 }
3.1.3啓動模塊
 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());
 }

3.2 AbpKernelModule

public sealed class AbpKernelModule : AbpModule
{
    public override void PreInitialize()
    {
        //註冊過濾器與基礎組件
        IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());

        IocManager.Register<IScopedIocResolver, ScopedIocResolver>(DependencyLifeStyle.Transient);
        IocManager.Register(typeof(IAmbientScopeProvider<>), typeof(DataContextAmbientScopeProvider<>), DependencyLifeStyle.Transient);

        AddAuditingSelectors();
        AddLocalizationSources();
        AddSettingProviders();
        AddUnitOfWorkFilters();
        ConfigureCaches();
        AddIgnoredTypes();
        AddMethodParameterValidators();
        AddDefaultNotificationDistributor();
    }

    public override void Initialize()
    {
        //
        foreach (var replaceAction in ((AbpStartupConfiguration)Configuration).ServiceReplaceActions.Values)
        {
            replaceAction();
        }

        IocManager.IocContainer.Install(new EventBusInstaller(IocManager));

        IocManager.Register(typeof(IOnlineClientManager<>), typeof(OnlineClientManager<>), DependencyLifeStyle.Singleton);
        IocManager.Register(typeof(IOnlineClientStore<>), typeof(InMemoryOnlineClientStore<>), DependencyLifeStyle.Singleton);

        IocManager.Register(typeof(EventTriggerAsyncBackgroundJob<>), DependencyLifeStyle.Transient);

        IocManager.RegisterAssemblyByConvention(typeof(AbpKernelModule).GetAssembly(),
            new ConventionalRegistrationConfig
            {
                InstallInstallers = false
            });
    }

    public override void PostInitialize()
    {
        RegisterMissingComponents();

        IocManager.Resolve<SettingDefinitionManager>().Initialize();
        IocManager.Resolve<FeatureManager>().Initialize();
        IocManager.Resolve<PermissionManager>().Initialize();
        IocManager.Resolve<LocalizationManager>().Initialize();
        IocManager.Resolve<NotificationDefinitionManager>().Initialize();
        IocManager.Resolve<NavigationManager>().Initialize();

        if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
        {
            var workerManager = IocManager.Resolve<IBackgroundWorkerManager>();
            workerManager.Start();
            workerManager.Add(IocManager.Resolve<IBackgroundJobManager>());
        }
    }
  }

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