当前位置: 首页 > news >正文

【ABP框架系列学习】模块系统(4)

0.引言

ABP提供了构建模块和通过组合模块以创建应用程序的基础设施。一个模块可以依赖于另外一个模块。通常,程序集可以认为是模块。如果创建多个程序集的应用程序,建议为每个程序集创建模块定义。

当前,模块系统主要集中在服务器,而不是客户端。

1.模块定义

模块是从ABP包中的AbpModule派生的类定义的。比如说开发一个可以用于不同应用程序的博客模块(Blog Module)。最简单的模块定义如下 :

public class MyBlogApplicationModule : AbpModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

模块定义类负责通过依赖注入注册类,如有必要(可以像上述事例按惯例完成)。它还可以配置应用程序和其它模块,给应用程序增加新的功能等等。

2.生命周期方法

ABP在程序启动和关闭时调用模块一些特定的方法。你可以重写这些方法以执行某些特定的任务。

ABP按照依赖顺序调用这些方法。如果模块A依赖模块B,那么模块B在模块A之前初始化。

启动方法执行准确的顺序:PreInitialize-B, PreInitialize-A, Initialize-B, Initialize-A, PostInitialize-B, PostInitialize-A。对于所有依赖关系图都是如此。关闭方法也是类似的,但顺序相反。

相关源码:模块启动时依次执行PreInitialize()、Initialize()、PostInitialize(),模块关闭时首先Reverse()、然后在逐个模块Shutdown()。

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

        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.");
        }

PreInitialize

当应用程序启动时,首先调用该方法。它是框架和其它模块初始化之前配置它们的首选方法。

你还可以在该方法中编写特定的代码,以便在依赖注入注册之前运行。例如,如果你创建一个传统的注册类,那么你应在该方法中使用IOCManager.AddConventionalRegisterer方法注册它们。

Initialize

该方法是依赖注入注册的地方,通过使用IocManager.RegisterAssemblyByConvention方法完成注册。如果想定义自定义的依赖注册,请见后续依赖注入章节。

PostInitialize

该方法在程序启动的最后调用。在这里解析依赖是安全的。

Shutdown

该方法在程序关闭时调用。

3.模块依赖(Module Dependencies)

一个模块可以依赖于另外的模块。你可以通过DependsOn特性显示声明依赖项,如下代码:

[DependsOn(typeof(MyBlogCoreModule))]
public class MyBlogApplicationModule : AbpModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

上述事例代码中,声明了MyBlogApplicationModule模块依赖于MyBlogCoreModule模块,那么MyBlogCoreModule模块应该在MyBlogApplicationModule模块之前完成初始化。

ABP可以从启动模块(start module)开始就递归的解析依赖关系,并相应地初始化它们。启动模块(start module)是最后进行初始化的模块。

4.插件模块

虽然模块从启动模块开始查找并遍历依赖关系,ABP还可以动态加载模块。AbpBootstrapper类中定义了PlugInSources属性,该属性可用于向动态加载的插件模块添加源。插件源可以是实现IPlugInSource接口的任何类。通过实现FolderPlugInSource类以从指定文件夹中的程序集获取插件模块。

ASP.NET CORE

ABP中ASP.NET CORE模块在AddAbp扩展方法中定义选项,用于在启动类中添加插件源:

services.AddAbp<MyStartupModule>(options =>
{
    options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns"));
});

也可以使用更简单的语法AddFolder扩展方法:

services.AddAbp<MyStartupModule>(options =>
{
    options.PlugInSources.AddFolder(@"C:\MyPlugIns");
});

ASP.NET MVC,Web API

对于传统的ASP.NET MVC应用程序,可以通过重写global.asax文件中Application_Start方法添加插件文件夹,如下代码:

public class MvcApplication : AbpWebApplication<MyStartupModule>
{
    protected override void Application_Start(object sender, EventArgs e)
    {
        AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns");
        //...
        base.Application_Start(sender, e);
    }
}

Controllers in PlugIns

如果你的模块包括MVC或Web API Controolers,ASP.NET不能查找你的控制器。为了克服这个问题,你可以修改global.asax文件,如下代码:

using System.Web;
using Abp.PlugIns;
using Abp.Web;
using MyDemoApp.Web;

[assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")]

namespace MyDemoApp.Web
{
    public class MvcApplication : AbpWebApplication<MyStartupModule>
    {
    }

    public static class PreStarter
    {
        public static void Start()
        {
            //...
            MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\");
            MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager();
        }
    }
}

附加程序集(Additional Assemblies)

默认实现IAssemblyFinder和ITypeFinder接口只能在这些程序集中查找模块程序集和类型。也可以在模块中重写GetAdditionalAssembliesy方法来包括其它程序集。

自定义模块方法(Custom Module Methods)

你的模块还可以拥有自定义的方法,并能在依赖于这个模块的其它模块中调用这个方法。假设MyModule2依赖于MyModule1,并想在PreInitialize方法中调用MyModule1模块中的方法。

public class MyModule1 : AbpModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }

    public void MyModuleMethod1()
    {
        //this is a custom method of this module
    }
}

[DependsOn(typeof(MyModule1))]
public class MyModule2 : AbpModule
{
    private readonly MyModule1 _myModule1;

    public MyModule2(MyModule1 myModule1)
    {
        _myModule1 = myModule1;
    }

    public override void PreInitialize()
    {
        _myModule1.MyModuleMethod1(); //Call MyModule1's method
    }

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

在上述代码中,通过构造函数把MyModule1注入到MyModule2,所以MyModule2可以调用MyModule1中的自定义方法,前提是MyModule2依赖于MyModule1。

模块配置(Module Configuration)

然而自定义方法可以用来配置模块,建议使用启动配置(startup configuration)系统来定义和设置模块的配置。

模块生命周期(Module Lifetime)

模块类自动注册为单实例对象(singleton)。

转载于:https://www.cnblogs.com/OlderGiser/p/10014200.html

相关文章:

  • C++类的大小——sizeof(class)
  • 挑战练习12.3 更多对话框
  • php简单随机实现发红包程序
  • java变量学习
  • 增加索引
  • 关于梯度下降 - 线性回归的
  • ethereum Pet Shop
  • 事件机制
  • Hibernate 注解映射
  • Python基础4
  • httprunner 使用总结
  • log日志模块得作用
  • 爬虫作业
  • 12.4今日博客
  • 线性回归于逻辑回归的区别
  • php的引用
  • [译]Python中的类属性与实例属性的区别
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • github指令
  • Laravel Mix运行时关于es2015报错解决方案
  • 第十八天-企业应用架构模式-基本模式
  • 力扣(LeetCode)56
  • 你对linux中grep命令知道多少?
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • (2.2w字)前端单元测试之Jest详解篇
  • (20050108)又读《平凡的世界》
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (十一)c52学习之旅-动态数码管
  • (一)基于IDEA的JAVA基础1
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转) Face-Resources
  • ***测试-HTTP方法
  • .FileZilla的使用和主动模式被动模式介绍
  • .net core使用ef 6
  • .NET 发展历程
  • .NET 中让 Task 支持带超时的异步等待
  • .NetCore部署微服务(二)
  • /bin/bash^M: bad interpreter: No such file or directory
  • @javax.ws.rs Webservice注解
  • @JsonSerialize注解的使用
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题
  • [] 与 [[]], -gt 与 > 的比较
  • []sim300 GPRS数据收发程序
  • []指针
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn
  • [C/C++随笔] char与unsigned char区别
  • [CTO札记]盛大文学公司名称对联
  • [github配置] 远程访问仓库以及问题解决
  • [hive]中的字段的数据类型有哪些
  • [HNOI2008]玩具装箱toy
  • [IDF]聪明的小羊
  • [JavaWeb学习] Spring Ioc和DI概念思想
  • [Mac软件]Goldie App v2.2 Mac黄金比例设计工具