• ABP之模块分析


    ABP之模块分析

    本篇作为我ABP介绍的第三篇文章,这次想讲下模块的,ABP文档已经有模块这方面的介绍,但是它只讲到如何使用模块,我想详细讲解下它模块的设计思路。

    ABP 框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块。在通常情况 下,一个程序集就可以看成是一个模块。在 ABP 框架中,一个模块通过一个类来定义,而这 个类要继承自 AbpModule。

    其实它的设计思路很简单:

    1、加载bin目录下的所有dll

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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有关

    1
    2
    3
    4
    5
    6
    7
    public static bool IsAbpModule(Type type)
    {
        return
            type.IsClass &&
            !type.IsAbstract &&
            typeof(AbpModule).IsAssignableFrom(type);
    }

    并递归获取没有只在所有的DependsOnAttribute,把他们填在到modules集合中(请详细看AbpModule.FindDependedModuleTypes方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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);
            }
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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循环注册了,并反转

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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中作者定义了三个事件,在实践应用在我们会依次执行下面三个方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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方法中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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模块它重写了其中两个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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

  • 相关阅读:
    sqlserver2005"此数据库没有有效所有者,因此无法安装数据库关系图支持对象"的解决方法
    重复表的复制操作
    重复表中连级下拉框采用数据源时,子级下拉框列表数据无法持久的问题
    SQL server2005连接与进程
    重复表操作
    XPath语法
    Request.ServerVariables 参数大全
    50个Sql语句
    Inside C++ new/delete and new[]/delete[]
    颜色空间
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4836980.html
Copyright © 2020-2023  润新知