10

Abp 源码分析(1):启动

 3 years ago
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.
neoserver,ios ssh client

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK