ABP模块系统
模块简介
整个ABP框架可以说是由模块组成的,也可以认为是每一个程序集就是一个模块,但也不是绝对的。一个程序集也可以有多个模块.
在我们从ABP官网创建项目时,可以发现每个层下面都是有个xxxxxModule.cs的文件这就是模块.
[DependsOn(typeof(MyStudyApplicationModule),typeof(MyStudyEntityFrameworkModule),typeof(AbpAspNetCoreModule),typeof(AbpAspNetCoreSignalRModule))]
public class MyStudyWebCoreModule : AbpModule
{
}
前一篇分析启动入口时,说过在中间件注册时(UseAbp)内部会从ioc容器中获取一个AbpBootStrapper对象并执行它的Initialize方法,Initialize则会从容器中获取一个AbpModuleManager模块管理者对象,执行AbpModuleManager的Initialize方法,创建AbpModuleCollection集合,然后执行LoadAllModules加载所有模块,加载所有模块完毕后,AbpModuleManager的Initialize方法结束,开始执行AbpModuleManager.StartModules启动所有的模块.
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());
}
可以看到上述代码中模块的生命周期方法:
- PreInitialize 预初始化
- Initialize 初始化
- PostInitialize 初始化完毕
但其实还有个 - Shutdown 销毁
看代码可以得知先执行的是 PreInitialize->Initialize->PostInitialize 而Shutdown则在上一篇分析过,其实是在AbpBootstrapper.Dispose方法中的ShutdownModules方法执行的,也就是程序退出的时候.
模块的用途就是在Abp框架加载的时候,执行一些初始化的操作.
例如.你可能会在xxxxxxModule看到如下代码.
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(xxxxxxModule).GetAssembly());
}
这其实就是模块的初始化方法,扫描当前模块所在程序集,往ioc容器注册里面需要依赖注入的类型.
其实Abp自身也有许多模块,例如AbpKernelModule这是Abp核心模块.
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();
}
PreInitialize
- 注册许多拦截器和基础组件
- 注册过滤器
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.RegisterAssemblyByConvention(typeof(AbpKernelModule).GetAssembly(),new ConventionalRegistrationConfig{InstallInstallers = false});
}
Initialize
- 执行替换服务的 Action(Abp 允许用户在预加载操作替换基础设施的服务)
- 注册事件总线基础设施
- 注册AbpKernelModule所在程序集需要依赖注入的服务
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>());
}
}
PostInitialize
- 注册一些基础设施
- 从容器中取出一些服务,执行初始化方法
- 启动所有后台工作者
public override void Shutdown()
{
if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
{
IocManager.Resolve<IBackgroundWorkerManager>().StopAndWaitToStop();
}
}
- Shutdown则很简单,停止所有后台工作.
发现模块与注册模块
搜索所有定义的模块类型
我们定义好自己的模块后,Abp又是如何知道的呢?
其实在Stratup的ConfigureServices方法中已经传入了启动模块
return services.AddAbp<MyStudyWebHostModule>();
在之前 AbpBootstrapper 的 Initialize 初始化方法当中通过调用 AbpModuleManager.Initialize(StartupModule)
方法来初始化,在其内部可以看到:
public virtual void Initialize(Type startupModule)
{
_modules = new AbpModuleCollection(startupModule);
LoadAllModules();
}
这里通过传入启动模块类型来初始化一个_modules(AbpModuleCollection)集合
internal class AbpModuleCollection : List<AbpModuleInfo>
{
public Type StartupModuleType { get; }
public AbpModuleCollection(Type startupModuleType)
{
StartupModuleType = startupModuleType;
}
}
创建_modules(AbpModuleCollection)后,执行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);
}
- FindAllModuleTypes 寻找所有ABP模块
- RegisterModules(moduleTypes) 向ioc容器以单例的形式注册找到的ABP模块
- CreateModules(moduleTypes, plugInModuleTypes) 通过ioc容器获取模块,并创建对应的AbpModuleInfops:为什么要在包装一层呢?其实主要是因为AbpModuleInfo里包含了
public List<AbpModuleInfo> Dependencies { get; }
这个属性,里面记录了该模块的所有依赖模块,为了保证模块加载顺序正确 - _modules.EnsureKernelModuleToBeFirst 将核心模块放在第一个位置,第一个初始化
- _modules.EnsureStartupModuleToBeLast 将启动模块放在最后一个位置,最后一个初始化
- SetDependencies 设置刚才所有创建的AbpModuleInfo的依赖顺序 ps:CreateModules里会把创建的AbpModuleInfo添加进 一开始通过启动模块类型创建的AbpModuleCollection集合
private AbpModuleCollection _modules;
这其实很容易想明白,启动模块依赖于其他模块.如果初始化的顺序不对就是有问题,所以最依赖最核心的模块必须是第一个初始化的。
那么如何发现的呢.
其实是通过反射获取了标记public class DependsOnAttribute : Attribute
这个特性,取到模块类型.
我们进入FindAllModuleTypes看看
private List<Type> FindAllModuleTypes(out List<Type> plugInModuleTypes)
{
plugInModuleTypes = new List<Type>();
var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType);
foreach (var plugInModuleType in _abpPlugInManager.PlugInSources.GetAllModules())
{
if (modules.AddIfNotContains(plugInModuleType))
{
plugInModuleTypes.Add(plugInModuleType);
}
}
return modules;
}
哟,可以看到刚进入方法就执行了一个静态方法FindDependedModuleTypesRecursivelyIncludingGivenModule
看到Recursively就清楚了这是一个递归方法... 入参是我们的启动模块类型
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);
}
}
这里先实例化一个type类型集合对象,保存我们所有的模块类型.然后作为入参传给AddModuleAndDependenciesRecursively
这里的话则是进行一系列的判断,之后先把入参module加入刚才的list集合,然后通过FindDependedModuleTypes寻找其依赖的模块
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;
}
找到所有的依赖模块后,遍历,递归....这样就把所有的依赖模块都找到了.
然后回到AbpModuleManager执行 RegisterModules(moduleTypes) 注册所有模块(单例)
模块的加载顺序排序初步确定
AbpModuleCollection 提供了两个方法,一个是 EnsureKernelModuleToBeFirst
一个是 EnsureStartupModuleToBeLast
public void EnsureKernelModuleToBeFirst()
{
EnsureKernelModuleToBeFirst(this);
}
public void EnsureStartupModuleToBeLast()
{
EnsureStartupModuleToBeLast(this, StartupModuleType);
}
public static void EnsureKernelModuleToBeFirst(List<AbpModuleInfo> modules)
{
var kernelModuleIndex = modules.FindIndex(m => m.Type == typeof(AbpKernelModule));
if (kernelModuleIndex <= 0)
{
//It's already the first!
return;
}
var kernelModule = modules[kernelModuleIndex];
modules.RemoveAt(kernelModuleIndex);
modules.Insert(0, kernelModule);
}
public static void EnsureStartupModuleToBeLast(List<AbpModuleInfo> modules, Type startupModuleType)
{
var startupModuleIndex = modules.FindIndex(m => m.Type == startupModuleType);
if (startupModuleIndex >= modules.Count - 1)
{
//It's already the last!
return;
}
var startupModule = modules[startupModuleIndex];
modules.RemoveAt(startupModuleIndex);
modules.Add(startupModule);
}
- EnsureKernelModuleToBeFirst 找到AbpKernelModule的索引.并通过索引获取到AbpKernelModule,先移除之前索引位置,然后从索引0处的位置插入AbpKernelModule,达到AbpKernelModule是处于集合中第一个的位置
- EnsureStartupModuleToBeLast 找到启动模块的索引,并通过索引获取到启动模块,先移除,然后插入到集合中最后一个位置.
所以模块在进行加载的时候,第一个加载的模块一定是核心模块,最后加载的模块肯定是启动模块。
确定每个模块的依赖
AbpModuleInfo
里面有个 public List<AbpModuleInfo> Dependencies { get; }
集合属性,这里面就是存当前模块所有依赖模块的。
而怎么存 存哪些模块进去,则是在加载所有模块时候 执行 SetDependencies
方法中确定的
private void SetDependencies()
{
foreach (var moduleInfo in _modules)
{
moduleInfo.Dependencies.Clear();
//Set dependencies for defined DependsOnAttribute attribute(s).
foreach (var dependedModuleType in AbpModule.FindDependedModuleTypes(moduleInfo.Type))
{
var dependedModuleInfo = _modules.FirstOrDefault(m => m.Type == dependedModuleType);
if (dependedModuleInfo == null)
{
throw new AbpInitializationException("Could not find a depended module " + dependedModuleType.AssemblyQualifiedName + " for " + moduleInfo.Type.AssemblyQualifiedName);
}
if ((moduleInfo.Dependencies.FirstOrDefault(dm => dm.Type == dependedModuleType) == null))
{
moduleInfo.Dependencies.Add(dependedModuleInfo);
}
}
}
}
- 经过CreateModules后AbpModuleCollection中已经存在了所有的依赖,所以这里是直接遍历,寻找当前模块 所依赖的 所有模块,存入当前模块的
public List<AbpModuleInfo> Dependencies { get; }
集合中
确定模块加载顺序排序完全确定
在所有模块基本信息加载完成之后,Abp 并没有在AbpModuleManager的Initialize
里面来进行这个重新排序操作,而是在 StartModules 方法里面来重新排序。
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.StartModules();
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString(), ex);
throw;
}
}
- _moduleManager.Initialize(StartupModule);//加载所有模块,确定每个模块所有的依赖模块,确定模块首尾顺序
- _moduleManager.StartModules();//在这里进行模块重新排序
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());
}
可以看到StartModules方法中首先进行的就是排序
public List<AbpModuleInfo> GetSortedModuleListByDependency()
{
var sortedModules = this.SortByDependencies(x => x.Dependencies);
EnsureKernelModuleToBeFirst(sortedModules);
EnsureStartupModuleToBeLast(sortedModules, StartupModuleType);
return sortedModules;
}
- SortByDependencies其实这里执行的是一个拓扑排序算法
- 然后还是确定AbpKernelModule为集合首,startupModule为集合尾,到这里,模块顺序就已经全部排序完成.
总结
1.Configure方法中会注册ABP中间件.
2.执行AbpApplicationBuilder的InitializeAbp
扩展方法,从ioc容器中获取abpBootstrapper
3.执行abpBootstrapper的Initialize方法,从Ioc容器中获取AbpModuleManager.
4.执行AbpModuleManager的Initialize方法.
- 根据启动模块的类型初始化一个AbpModuleCollection集合
- 执行LoadAllModules方法
- 执行FindAllModuleTypes方法.递归找到所有模块.
- 执行RegisterModules方法:以单例的形式注册模块到ioc容器
- 执行CreateModules方法:
- 从ioc容器获取模块,设置基本属性(IocManager,Configuration)
- 将模块对象包装成AbpModuleInfo对象,添加进AbpModuleCollection集合中
- 执行AbpModuleCollection的
EnsureKernelModuleToBeFirst
和EnsureStartupModuleToBeLast
,确定集中模块基本首尾顺序(AbpKernelModule索引为0,启动模块索引为最后一位) - 执行SetDependencies方法:遍历AbpModuleCollection,找到当前ModuleInfo的所有依赖模块,添加进moduleInfo.Dependencies属性集合中
5.执行AbpModuleManager的StartModules方法
- 将AbpModuleCollection再次排序(拓扑排序),保证模块执行顺序的正确
- 执行所有模块的PreInitialize方法
- 执行所有模块的Initialize方法
- 执行所有模块的PostInitialize方法