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

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

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

AddAbp()

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

app.UseAbp()

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

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

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

AbpBootStrapper.Initialize()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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 方法,将一些核心组件通过安装器注入到容器当中。

 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
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 初始化所有核心模块的配置项。 之后就是最重要的初始化模块操作了。

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 才是真正的启动模块:

1
2
3
4
5
6
7
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 被释放的时候,进行调用。

1
2
3
4
5
6
7
8
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

  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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
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 原有的功能模块实现。

Built with Hugo
主题 StackJimmy 设计