Abp 源码分析(1):启动
source link: http://blog.tubumu.com/2019/09/27/abp-analysis-01/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Abp
是一个开源应用程序框架,专注于基于 ASP.NET Core
的 Web 应用程序开发,但也支持开发其他类型的应用程序。
本文先分析相关的几个类型,再分析 Abp 的启动流程。
二、AbpApplication
这里的 Application
并非领域驱动设计( DDD
)的应用程序层。Abp 是一个框架,运行于 .Net Core 之上;AbpApplication
是一个应用,运行于 Abp 之上 。AbpApplication 主要负责模块的加载和卸载。
从代码上看,Application 是实现了 IAbpApplication
接口的类,有三个实现了 IAbpApplication 接口的类,继承关系见下图。
1
2
3
4
5
graph BT
D[AbpApplicationWithExternalServiceProvider] --> C[AbpApplicationBase]
E[AbpApplicationWithInternalServiceProvider] --> C[AbpApplicationBase]
C --> B[IAbpApplication]
B --> A[IModuleContainer]
AbpApplicationBase
是抽象类。AbpApplicationWithExternalServiceProvider
一般用于 AspNetCore
应用,使用 AspNetCore 的 service collection 创建 service provider;而 AbpApplicationWithInternalServiceProvider
一般用于其他应用,使用自建的 service collection 创建 service provider 。
另外,IAbpApplication
接口继承了 IModuleContainer
接口,后者定义了一个 IAbpModuleDescriptor
元素的只读集合。
三、IModuleContainer 和 IAbpModuleDescriptor
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
// File: src\Volo.Abp.Core\Volo\Abp\Modularity\IModuleContainer.cs
namespace Volo.Abp.Modularity
{
public interface IModuleContainer
{
[NotNull]
IReadOnlyList<IAbpModuleDescriptor> Modules { get; }
}
}
// File: src\Volo.Abp.Core\Volo\Abp\Modularity\IAbpModuleDescriptor.cs
namespace Volo.Abp.Modularity
{
public interface IAbpModuleDescriptor
{
Type Type { get; }
Assembly Assembly { get; }
IAbpModule Instance { get; }
bool IsLoadedAsPlugIn { get; }
IReadOnlyList<IAbpModuleDescriptor> Dependencies { get; }
}
}
IAbpModuleDescriptor
用于保存应用包含的模块的类型、所在程序集、实例、是否以插件形式加载和依赖的其他模块。其实模块的类型和所在程序集是冗余的,通过实例对象也可以获取到。
备注:IsLoadedAsPlugIn 表示模块是否已插件形式加载。以插件形式加载的目的在这里不做分析。不过,一个以插件形式加载的模块,会创建两个
AbpModuleDescriptor
实例。
四、IAbpApplication
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
// File: src\Volo.Abp.Core\Volo\Abp\IAbpApplication.cs
namespace Volo.Abp
{
public interface IAbpApplication : IModuleContainer, IDisposable
{
/// <summary>
/// Type of the startup (entrance) module of the application.
/// 应用启动(入口)模块的类型。
/// </summary>
Type StartupModuleType { get; }
/// <summary>
/// List of services registered to this application.
/// Can not add new services to this collection after application initialize.
/// 注册到应用程序的服务列表。
/// 在应用初始化后,不能添加新的服务到集合。
/// </summary>
IServiceCollection Services { get; }
/// <summary>
/// Reference to the root service provider used by the application.
/// This can not be used before initialize the application.
/// 引用应用使用的根 service provider 。
/// 在应用初始化之前不能使用。
/// </summary>
IServiceProvider ServiceProvider { get; }
/// <summary>
/// Used to gracefully shutdown the application and all modules.
/// 用于正常关闭应用程序和所有模块。
/// </summary>
void Shutdown();
}
}
StartupModuleType
属性用于模块加载时查找应用依赖的其他模块。Services
属性用于将 AbpApplication 自身注册为 IoC 单例,以及创建 ServiceProvider
属性。ServiceProvider
属性当然用于从 IoC 中获取实例。Shutdown
方法用于正常关闭应用程序和所有模块。
五、AbpApplicationBase
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
// File: src\Volo.Abp.Core\Volo\Abp\AbpApplicationBase.cs
namespace Volo.Abp
{
public abstract class AbpApplicationBase : IAbpApplication
{
[NotNull]
public Type StartupModuleType { get; }
public IServiceProvider ServiceProvider { get; private set; }
public IServiceCollection Services { get; }
public IReadOnlyList<IAbpModuleDescriptor> Modules { get; }
internal AbpApplicationBase(
[NotNull] Type startupModuleType,
[NotNull] IServiceCollection services,
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction)
{
Check.NotNull(startupModuleType, nameof(startupModuleType));
Check.NotNull(services, nameof(services));
// 简单赋值
StartupModuleType = startupModuleType;
Services = services;
// ObjectAccessor 实现了一种"延迟"注册具体服务的机制。
services.TryAddObjectAccessor<IServiceProvider>();
// 附加的服务注册、配置、插件源。比如模板项目里 Startup 中的:options.UseAutofac();
var options = new AbpApplicationCreationOptions(services);
optionsAction?.Invoke(options);
// 将自身注册为 IAbpApplication 和 IModuleContainer 的单例。
services.AddSingleton<IAbpApplication>(this);
services.AddSingleton<IModuleContainer>(this);
// File: src\Volo.Abp.Core\Volo\Abp\Internal\InternalServiceCollectionExtensions.cs
// 注册核心服务(Options、Logging 和 AddLocalization)
services.AddCoreServices();
// 注册核心 Abp 服务
services.AddCoreAbpServices(this, options);
// 加载模块
Modules = LoadModules(services, options);
}
/// <summary>
/// 关闭应用。
/// </summary>
public virtual void Shutdown()
{
using (var scope = ServiceProvider.CreateScope())
{
scope.ServiceProvider
.GetRequiredService<IModuleManager>()
.ShutdownModules(new ApplicationShutdownContext(scope.ServiceProvider));
}
}
public virtual void Dispose()
{
//TODO: Shutdown if not done before?
}
/// <summary>
/// 设置 service provider。
/// </summary>
protected virtual void SetServiceProvider(IServiceProvider serviceProvider)
{
// 简单赋值
ServiceProvider = serviceProvider;
ServiceProvider.GetRequiredService<ObjectAccessor<IServiceProvider>>().Value = ServiceProvider;
}
/// <summary>
/// AbpApplicationWithExternalServiceProvider` 和 `AbpApplicationWithInternalServiceProvider` 的 Initialize 方法调用。
/// 即,在初始化 AbpApplication 的时候初始化模块。
/// </summary>
protected virtual void InitializeModules()
{
using (var scope = ServiceProvider.CreateScope())
{
scope.ServiceProvider
.GetRequiredService<IModuleManager>()
.InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider));
}
}
/// <summary>
/// 加载模块。
/// </summary>
private IReadOnlyList<IAbpModuleDescriptor> LoadModules(IServiceCollection services, AbpApplicationCreationOptions options)
{
return services
.GetSingletonInstance<IModuleLoader>()
.LoadModules(
services,
StartupModuleType,
options.PlugInSources
);
}
}
}
相关类型:
ObjectAccessor
ApplicationShutdownContext
IModuleManager
IModuleLoader
六、AbpApplicationWithExternalServiceProvider
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
// File: src\Volo.Abp.Core\Volo\Abp\AbpApplicationWithExternalServiceProvider.cs
namespace Volo.Abp
{
internal class AbpApplicationWithExternalServiceProvider : AbpApplicationBase, IAbpApplicationWithExternalServiceProvider
{
public AbpApplicationWithExternalServiceProvider(
[NotNull] Type startupModuleType,
[NotNull] IServiceCollection services,
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction
) : base(
startupModuleType,
services,
optionsAction)
{
// 将自身注册到 IoC 容器
services.AddSingleton<IAbpApplicationWithExternalServiceProvider>(this);
}
public void Initialize(IServiceProvider serviceProvider)
{
Check.NotNull(serviceProvider, nameof(serviceProvider));
// 简单调用 AbpApplicationBase 的 SetServiceProvider 方法
SetServiceProvider(serviceProvider);
// 简单调用 AbpApplicationBase 的 InitializeModules 方法
InitializeModules();
}
}
}
七、AbpApplicationWithInternalServiceProvider
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
// File: src\Volo.Abp.Core\Volo\Abp\AbpApplicationWithInternalServiceProvider.cs
namespace Volo.Abp
{
internal class AbpApplicationWithInternalServiceProvider : AbpApplicationBase, IAbpApplicationWithInternalServiceProvider
{
// 定义子 service scope
public IServiceScope ServiceScope { get; private set; }
public AbpApplicationWithInternalServiceProvider(
[NotNull] Type startupModuleType,
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction
) : this(
startupModuleType,
new ServiceCollection(),
optionsAction)
{
}
private AbpApplicationWithInternalServiceProvider(
[NotNull] Type startupModuleType,
[NotNull] IServiceCollection services,
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction
) : base(
startupModuleType,
services,
optionsAction)
{
// 将自身注册到 IoC 容器
Services.AddSingleton<IAbpApplicationWithInternalServiceProvider>(this);
}
public void Initialize()
{
// 创建子 service scope
ServiceScope = Services.BuildServiceProviderFromFactory().CreateScope();
// 简单调用 AbpApplicationBase 的 SetServiceProvider 方法
SetServiceProvider(serviceProvider);
// 简单调用 AbpApplicationBase 的 InitializeModules 方法
InitializeModules();
}
public override void Dispose()
{
base.Dispose();
// 子 service scope子 service scope
ServiceScope.Dispose();
}
}
}
八、Abp AspNetCore 应用的启动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// File: src\Volo.Abp.Core\Microsoft\Extensions\DependencyInjection\ServiceCollectionApplicationExtensions.cs
services.AddApplication<BookStoreWebModule>(options =>
{
// File: src\Volo.Abp.Autofac\Autofac\Extensions\DependencyInjection\ServiceCollectionExtensions.cs
options.UseAutofac();
});
// File: src\Volo.Abp.Core\Microsoft\Extensions\DependencyInjection\ServiceCollectionCommonExtensions.cs
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
// File: src\Volo.Abp.AspNetCore\Microsoft\AspNetCore\Builder\AbpApplicationBuilderExtensions.cs
app.InitializeApplication();
}
}
ConfigureServices
方法可以无返回值或返回 IServiceProvider。如果用 .NET Core CLI
创建 AspNetCore 应用,ConfigureServices
方法默认无返回值的,这种情况会尝试其他方式来创建 service provider(详见:StartupLoader
)。Abp 决定自行构建 service provider 。UseAutofac
会创建一个能够产出 service provider ( AutofacServiceProvider
) 的 AbpAutofacServiceProviderFactory
对象,将之单例注册到 IoC 容器中。BuildServiceProviderFromFactory
找到 AbpAutofacServiceProviderFactory 并产出 AutofacServiceProvider
对象。BookStoreWebModule
是一个 AbpModule。与其他模块不同的是,该模块是启动模块。
InitializeApplication
扩展方法主要调用 IAbpApplicationWithExternalServiceProvider
的 Initialize
方法。核心作用就是初始化模块。
总之,在执行 Startup 的 ConfigureServices 方法时加载模块,在执行 Configure 方法时初始化模块。
https://docs.abp.io/zh-Hans/abp/latest
https://www.cnblogs.com/myzony/p/10722506.html
https://docs.autofac.org/en/latest/integration/aspnetcore.html#asp-net-core-3-0-and-generic-hosting
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK