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