本文通过搭建一个基于ABP简单的WebAPI Demo了解ABP的初始化过程。
TestAbp.IService:
IMyService中主要定义了一个SayHello的接口
using Abp.Application.Services;
namespace TestAbp.IService
{
public interface IMyService: ITransientDependency
{
string SayHello(string name);
}
}
TestAbp.Service
MyService实现SayHello:
using TestAbp.IService;
namespace TestAbp.Service
{
public class MyService : IMyService
{
public string SayHello(string name)
{
return $"hello {name}!";
}
}
}
abp是基于模块化思想设计的,A模块可以依赖B模块,我们对于service层先定义为一个模块,继承AbpModule:
using Abp.Modules;
using Abp.Reflection.Extensions;
namespace TestAbp.Service
{
public class TestAbpServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(TestAbpServiceModule).GetAssembly());
}
}
}
TestABP.WebAPI
定义接口,依赖AbpController,AbpController继承自Controller:
using Abp.AspNetCore.Mvc.Controllers;
using Abp.Web.Models;
using Microsoft.AspNetCore.Mvc;
using TestAbp.IService;
namespace TestABP.WebAPI.Controllers
{
[Route("api/[controller]")]
[DontWrapResult]
public class MyController : AbpController
{
private readonly IMyService _myService;
public MyController(IMyService myService)
{
_myService = myService;
}
[HttpGet("sayhello")]
public string SayHello(string name)
{
return _myService.SayHello(name);
}
}
}
同理,在webapi层,也定义模块TestABPWebAPIServiceModule,可以通过看出DependsOn看出,当前模块依赖AbpAspNetCoreModule和我们刚才创建的TestAbpServiceModule:
using Abp.AspNetCore;
using Abp.Modules;
using Abp.Reflection.Extensions;
using TestAbp.Service;
namespace TestABP.WebAPI
{
[DependsOn(typeof(AbpAspNetCoreModule),typeof(TestAbpServiceModule))]
public class TestABPWebAPIServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(TestABPWebAPIServiceModule).GetAssembly());
}
}
}
在 startup时,我们只要配置下services.AddAbp和app.UseAbp:
using Abp.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace TestABP.WebAPI
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return services.AddAbp<TestABPWebAPIServiceModule>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAbp();
app.UseMvc();
}
}
}
1.以前我们需要如下DI
services.AddSingleton<IMyService, MyService>();
现在ABP是通过
IocManager.RegisterAssemblyByConvention(typeof(TestABPWebAPIServiceModule).GetAssembly());
那是在什么时候被调用的呢?
2.services.AddAbp和app.UseAbp分别做了哪些事情?
我们就来看看services.AddAbp和app.UseAbp内部的处理。
从下面代码看得出,总共3个步骤,通过核心启动类AbpBootstrapper ,负责框架的初始化,第3个步骤使用Castle替代自带的 Ioc 容器,那么Castle作为IocManager 又是在哪里定义的呢?往下看:
///
/// Integrates ABP to AspNet Core.
///
public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
where TStartupModule : AbpModule
{
//1.创建AbpBootstrapper
var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);
//2.配置
ConfigureAspNetCore(services, abpBootstrapper.IocManager);
//3.使用Castle替代自带的 Ioc 容器
return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
}
先来看看创建AbpBootstrapper,发现Create一个AbpBootstrapper后,放到容器中,方便后面获取:
private static AbpBootstrapper AddAbpBootstrapper<TStartupModule>(IServiceCollection services, Action<AbpBootstrapperOptions> optionsAction)
where TStartupModule : AbpModule
{
var abpBootstrapper = AbpBootstrapper.Create<TStartupModule>(optionsAction);
//对Create后的abpBootstrapper进行注入
services.AddSingleton(abpBootstrapper);
return abpBootstrapper;
}
再往里面,可以看出Create主要做了定义了StartupModule(开始的module,即demo中的APIModule)、IocManager 、PlugInSources(如果需要使用外部的dll)、AbpBootstrapper自身需要的_logger :
///
/// 创建一个新的 实例.
///
private AbpBootstrapper([NotNull] Type startupModule, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
{
var options = new AbpBootstrapperOptions();
optionsAction?.Invoke(options);
StartupModule = startupModule;
IocManager = options.IocManager;
PlugInSources = options.PlugInSources;
_logger = NullLogger.Instance;
}
这里的IocManager ,在AbpBootstrapperOptions的构造函数里就可以看到,使用Castle作为容器管理器,所以有了最外面的第3步骤使用Castle作为IocManager:
public AbpBootstrapperOptions()
{
//使用Castle作为容器
IocManager = Abp.Dependency.IocManager.Instance;
//初始化插件列表
PlugInSources = new PlugInSourceList();
}
那第2个步骤ConfigureAspNetCore(services, abpBootstrapper.IocManager);又在做什么呢,主要是对mvc模式下,abp自己的配置和替换,我做了下注释
private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver)
{
//注入http上下文和action上下文
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
//替换DI创建IControllerActivator
//DefaultControllerActivator使用TypeActivatorCache来创建控制器,ServiceBasedControllerActivator直接从 DI 容器中获取控制器
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
//同理,使用DI创建IViewComponentActivator
services.Replace(ServiceDescriptor.Singleton<IViewComponentActivator, ServiceBasedViewComponentActivator>());
//替换验证的过滤器
services.Replace(ServiceDescriptor.Transient<AutoValidateAntiforgeryTokenAuthorizationFilter, AbpAutoValidateAntiforgeryTokenAuthorizationFilter>());
services.Replace(ServiceDescriptor.Transient<ValidateAntiforgeryTokenAuthorizationFilter, AbpValidateAntiforgeryTokenAuthorizationFilter>());
//添加 Feature Provider,判断是否为控制器
var partManager = services.GetSingletonServiceOrNull<ApplicationPartManager>();
partManager?.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(iocResolver));
//配置为abp的MVCJSON序列化方案相关
services.Configure<MvcJsonOptions>(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new AbpMvcContractResolver(iocResolver)
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
//添加abp相关的到MVC配置
services.Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(services);
});
//Razor的abp配置
services.Insert(0,
ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>(
new ConfigureOptions<RazorViewEngineOptions>(
(options) =>
{
options.FileProviders.Add(new EmbeddedResourceViewFileProvider(iocResolver));
}
)
)
);
}
通过前面的services.AddAbp,我们已经知道创建了AbpBootstrapper,并使用Castle作为容器管理器,接下来看看app.UseAbp里面发生了什么。
首先看到主要调用了InitializeAbp:
public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction)
{
//...
//初始化abp
InitializeAbp(app);
//...
}
InitializeAbp主要包含以下几项:
private static void InitializeAbp(IApplicationBuilder app)
{
//获取刚才注入的abpBootstrapper实例
var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
//进行初始化
abpBootstrapper.Initialize();
//当网站关闭时,调用 AbpBootstrapper 对象的 Dispose() 方法
var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
}
再往里面abpBootstrapper.Initialize()看,前面都是一些相关的初始化,最后的是重点,会对我们定义模块依赖进行注册:
///
/// Initializes the ABP system.
///
public virtual void Initialize()
{
ResolveLogger();
try
{
//检查是否已经注册过AbpBootstrapper,如没有再将当前实例注册
RegisterBootstrapper();
//AbpCore相关初始化注册
IocManager.IocContainer.Install(new AbpCoreInstaller());
//Abp插件(可以来自外部dll)相关初始化
IocManager.Resolve<AbpPlugInManager>().PlugInSources.AddRange(PlugInSources);
//AbpStartup相关配置初始化(略过)
IocManager.Resolve<AbpStartupConfiguration>().Initialize();
//重点:根据StartupModule标名的 [DependsOn(typeof(... 安装顺序初始化
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
_moduleManager.StartModules();
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString(), ex);
throw;
}
}
往_moduleManager.Initialize进去看,定义了一个AbpModuleCollection对象,通过LoadAllModules来填充:
public virtual void Initialize(Type startupModule)
{
_modules = new AbpModuleCollection(startupModule);
LoadAllModules();
}
LoadAllModules根据DependsOn的特性,初始化了各个模块:
private void LoadAllModules()
{
Logger.Debug("Loading Abp modules...");
List<Type> plugInModuleTypes;
//找到DependsOn特性上的类型列表
var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();
Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");
RegisterModules(moduleTypes);
//各模块进行初始化,如果不是继承AbpModule会在次抛出异常
CreateModules(moduleTypes, plugInModuleTypes);
_modules.EnsureKernelModuleToBeFirst();
_modules.EnsureStartupModuleToBeLast();
//设置依赖关系
SetDependencies();
Logger.DebugFormat("{0} modules loaded.", _modules.Count);
}
初始化完成后, 那就是最后一步啦,开始运行加载进来的模块,也就是_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());
}
那么我们定义的模块Initialize()方法就在这里被执行了。
namespace TestAbp.Service
{
public class TestAbpServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(TestAbpServiceModule).GetAssembly());
}
}
}
好 , 整个abp初始化过程就完成了,通过本篇了解到abp的初始化过程,讲的还是很粗,很多细节没列出来,还是要看自己去看。同时我们也知道了我们自己的abpmodule是如何被初始化的。有问题欢迎交流。
IocManager.RegisterAssemblyByConvention(Assembly assembly)是如何知道要DI哪些的,是否会把所有的都加入到IOC容器中?
其实不会,通过源码,发现只有BasedOn ITransientDependency、ISingletonDependency、IInterceptor才会进行注册到IOC容器:
public void RegisterAssembly(IConventionalRegistrationContext context)
{
//Transient
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ITransientDependency>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
//Singleton
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ISingletonDependency>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleSingleton()
);
//Windsor Interceptors
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<IInterceptor>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.LifestyleTransient()
);
}