Abp 源码分析(1):启动

一、概述

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 扩展方法主要调用 IAbpApplicationWithExternalServiceProviderInitialize 方法。核心作用就是初始化模块。

总之,在执行 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