ABP之模塊分析


本篇作為我ABP介紹的第三篇文章,這次想講下模塊的,ABP文檔已經有模塊這方面的介紹,但是它只講到如何使用模塊,我想詳細講解下它模塊的設計思路。

ABP 框架提供了創建和組裝模塊的基礎,一個模塊能夠依賴於另一個模塊。在通常情況 下,一個程序集就可以看成是一個模塊。在 ABP 框架中,一個模塊通過一個類來定義,而這 個類要繼承自 AbpModule。

 

其實它的設計思路很簡單:

1、加載bin目錄下的所有dll

    public class WebAssemblyFinder : IAssemblyFinder
    {
        /// <summary>
        /// This return all assemblies in bin folder of the web application.
        /// </summary>
        /// <returns>List of assemblies</returns>
        public List<Assembly> GetAllAssemblies()
        {
            var assembliesInBinFolder = new List<Assembly>();

            var allReferencedAssemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();
            var dllFiles = Directory.GetFiles(HttpRuntime.AppDomainAppPath + "bin\\", "*.dll", SearchOption.TopDirectoryOnly).ToList();

            foreach (string dllFile in dllFiles)
            {
                var locatedAssembly = allReferencedAssemblies.FirstOrDefault(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), AssemblyName.GetAssemblyName(dllFile)));
                if (locatedAssembly != null)
                {
                    assembliesInBinFolder.Add(locatedAssembly);
                }
            }

            return assembliesInBinFolder;
        }
    }

2、循環判斷獲取所有與AbpModule的Types有關

        public static bool IsAbpModule(Type type)
        {
            return
                type.IsClass &&
                !type.IsAbstract &&
                typeof(AbpModule).IsAssignableFrom(type);
        }

並遞歸獲取沒有只在所有的DependsOnAttribute,把他們填在到modules集合中(請詳細看AbpModule.FindDependedModuleTypes方法)

        private static ICollection<Type> AddMissingDependedModules(ICollection<Type> allModules)
        {
            var initialModules = allModules.ToList();
            foreach (var module in initialModules)
            {
                FillDependedModules(module, allModules);
            }

            return allModules;
        }

        private static void FillDependedModules(Type module, ICollection<Type> allModules)
        {
            foreach (var dependedModule in AbpModule.FindDependedModuleTypes(module))
            {
                if (!allModules.Contains(dependedModule))
                {
                    allModules.Add(dependedModule);
                    FillDependedModules(dependedModule, allModules);
                }
            }
        }
        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.IsDefined(typeof(DependsOnAttribute), true))
            {
                var dependsOnAttributes = moduleType.GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();
                foreach (var dependsOnAttribute in dependsOnAttributes)
                {
                    foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes)
                    {
                        list.Add(dependedModuleType);
                    }
                }
            }

            return list;
        }

所有關於模塊的重要代碼都在AbpModuleManager中,在上面我們已經加載了所有的模塊的類型,那么ABP到底有多少個Modules呢

在我下載的Demo中包含了十三個Module,都繼承字AbpModule類

 

3、既然我得到了所有的moduleTypes了,那么我就通過Castle Windsor循環注冊了,並反轉

        private void LoadAll()
        {
            Logger.Debug("Loading Abp modules...");
            //通過bin加載所有的module集合
            var moduleTypes = AddMissingDependedModules(_moduleFinder.FindAll());
            Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");

            //通過castle windsor注冊所有的模塊 Register to IOC container.
            foreach (var moduleType in moduleTypes)
            {
                if (!AbpModule.IsAbpModule(moduleType))
                {
                    throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
                }

                if (!_iocManager.IsRegistered(moduleType))
                {
                    _iocManager.Register(moduleType);
                }
            }

            //模塊反轉並添加到_modules中 Add to module collection
            foreach (var moduleType in moduleTypes)
            {
                var moduleObject = (AbpModule)_iocManager.Resolve(moduleType);

                moduleObject.IocManager = _iocManager;
                moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();

                _modules.Add(new AbpModuleInfo(moduleObject));

                Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
            }

            //確保AbpKernelModule是_modules中第一個module,AbpKernelModule must be the first module
            var startupModuleIndex = _modules.FindIndex(m => m.Type == typeof(AbpKernelModule));
            if (startupModuleIndex > 0)
            {
                var startupModule = _modules[startupModuleIndex];
                _modules.RemoveAt(startupModuleIndex);
                _modules.Insert(0, startupModule);
            }

            SetDependencies();

            Logger.DebugFormat("{0} modules loaded.", _modules.Count);
        }

上面代碼有注釋,詳細請看注釋

 

4、就是初始化所有模塊的事件,早AbpModule中作者定義了三個事件,在實踐應用在我們會依次執行下面三個方法

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

在一個應用中,ABP 框架調用了 Module 模塊的一些指定的方法來進行啟動和關閉模塊的 操作。我們可以重載這些方法來完成我們自己的任務。 ABP 框架通過依賴關系的順序來調用這些方法,

假如:模塊 A 依賴於模塊 B,那么模塊 B 要在模塊 A 之前初始化,模塊啟動的方法順序如下:

1) PreInitialize-B

2) PreInitialize-A

3) Initialize-B

4) Initialize-A

5) PostInitialize-B

6) PostInitialize-A

 

那么我們是怎么執行上面的方法的呢,方案在AbpModuleManager的InitializeModules方法中

        public virtual void InitializeModules()
        {
            LoadAll();

            var sortedModules = _modules.GetSortedModuleListByDependency();

            sortedModules.ForEach(module => module.Instance.PreInitialize());
            sortedModules.ForEach(module => module.Instance.Initialize());
            sortedModules.ForEach(module => module.Instance.PostInitialize());
        }

那么我們在自定義模塊的時候是要重寫上面三個方法的,有點像管道的事件,我們會依次執行這些事件,現在我們隨便看個AbpEntityFrameworkModule模塊它重寫了其中兩個

       public override void PreInitialize()
        {
            IocManager.AddConventionalRegistrar(new EntityFrameworkConventionalRegisterer());
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

            IocManager.IocContainer.Register(
                Component.For(typeof (IDbContextProvider<>))
                    .ImplementedBy(typeof (UnitOfWorkDbContextProvider<>))
                    .LifestyleTransient()
                );
            
            RegisterGenericRepositories();
        }

一般的我們都要在Initialize方法中加上這句IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); 也就是注冊當前程序集,IOC初始化用的哦,好了,至此終於把ABP模塊的思路講完啦,大家可以配合ABP的文檔的相關章節進行研究,希望對初學者有幫助。

 

參考文章:

https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM