本文通过搭建一个基于ABP简单的WebAPI Demo了解ABP的初始化过程。

简单的WebAPI DEMO

首先让我们建立一个项目:

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 又是在哪里定义的呢?往下看:

services.AddAbp

       /// <summary>/// Integrates ABP to AspNet Core./// </summary>public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)where TStartupModule : AbpModule{//1.创建AbpBootstrappervar 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 :

/// <summary>/// 创建一个新的 <see cref="AbpBootstrapper"/> 实例./// </summary>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创建IViewComponentActivatorservices.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));})));}

app.UseAbp

通过前面的services.AddAbp,我们已经知道创建了AbpBootstrapper,并使用Castle作为容器管理器,接下来看看app.UseAbp里面发生了什么。
首先看到主要调用了InitializeAbp:

public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction){//...//初始化abpInitializeAbp(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()看,前面都是一些相关的初始化,最后的是重点,会对我们定义模块依赖进行注册:

/// <summary>/// Initializes the ABP system./// </summary>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){//Transientcontext.IocManager.IocContainer.Register(Classes.FromAssembly(context.Assembly).IncludeNonPublicTypes().BasedOn<ITransientDependency>().If(type => !type.GetTypeInfo().IsGenericTypeDefinition).WithService.Self().WithService.DefaultInterfaces().LifestyleTransient());//Singletoncontext.IocManager.IocContainer.Register(Classes.FromAssembly(context.Assembly).IncludeNonPublicTypes().BasedOn<ISingletonDependency>().If(type => !type.GetTypeInfo().IsGenericTypeDefinition).WithService.Self().WithService.DefaultInterfaces().LifestyleSingleton());//Windsor Interceptorscontext.IocManager.IocContainer.Register(Classes.FromAssembly(context.Assembly).IncludeNonPublicTypes().BasedOn<IInterceptor>().If(type => !type.GetTypeInfo().IsGenericTypeDefinition).WithService.Self().LifestyleTransient());}

ABP框架(.Net Core)-分析初始化过程相关推荐

  1. ABP框架 .net core 版本的安装与运行(vue模板)

    1.首先当然去官网下载.net core vue模板 2.解压后用vscode打开aspnet-core 文件夹(后台项目) 3.Ctrl+~ 打开终端窗口,先biild一下,命令:dotnet bu ...

  2. hadoop作业初始化过程详解(源码分析第三篇)

    (一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...

  3. [Abp vNext 源码分析] - 1. 框架启动流程分析

    一.简要说明 本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的.总的来说 ,Abp vNext 比起 ABP 框架 ...

  4. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. Nginx源码分析-启动初始化过程(一)

    Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务以外,也必定是所有功能模块的入口之处.Nginx的初始化工作 ...

  6. nginx源码分析(2)——http模块的初始化过程

    前一篇文章介绍了nginx的启动初始化过程,包括了所有模块的初始化过程,比如http模块.事件模块等.这里再详细介绍一下http模块的启动过程,还记得在前一篇文章中提到过ngx_conf_parse函 ...

  7. Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS之部署到Linux

    尝试新的开发组合:Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ext JS Asp.NET Core+ABP框架+IdentityServer4+MySQL+Ex ...

  8. ABP框架官网例子实践(2)(ASP.NET core+Multi Page Web Application)

    ABP框架官网例子实践(1)(ASP.NET core+Multi Page Web Application) 第三步:开始在Application中进行编写代码 1.为app service定义一个 ...

  9. 使用.net core和abp框架实现动态webapi的简单说明

    目录 背景 代码 其他 背景 最近开始准备用.net core 3.1做一个项目,最终选择了abp框架作为后台webapi实现,从而实现一个以vue作为前端的SPA项目.而作为api对外输出,最好是能 ...

最新文章

  1. 《课程的反思与重建--我们需要什么样的课程观》之心得体会
  2. 浙江大学首次跻身全球50强,上海交大论文发表量全球第四 | QS最新世界大学排名...
  3. 性价比泛滥后,网易严选情怀路线还能否继续吃香?
  4. C++Builder 2010深入TApplication类之属性
  5. linux u32,如何在程序中使用u32这个类型啊。
  6. php的list函数
  7. 生成注释_SOLIDWORKS DimXpert 自动生成注释
  8. Illustrator 教程,如何在 Illustrator 中描摹对象?
  9. 用python智能修复度盘防和谐链接~
  10. token实现单点登录原理
  11. 京东联盟api获取数据
  12. macOS如何查看pkg安装包中的内部文件
  13. 电脑WLAN/WIFI搜索不到网络
  14. 12星座之追女必杀技~
  15. 证书类型、自签CA证书、https双向认证(一篇就懂系列)
  16. 四十八 停电与打牌(中) 我在软件园的那些日子里
  17. ubuntu 配置本地源
  18. 深圳赛意信息 怎么样_深圳自动瓶坯检查机怎么样
  19. 电信isag接口java_使用ag-grid进行国际化
  20. JavaScript面试精讲(六)——说说你经常使用到的array方法

热门文章

  1. 要考PMP项目管理认证,选择机构是选PMI还是IPA呢?
  2. java jolt_java – Jolt条件规范
  3. Xilinx zynq系列pcie xdma通信(二):下位机PS端
  4. 笔试:求数组左边减去右边的最大值 / 右边减去左边的最大值
  5. android 疯狂足球原码,基于Android的疯狂足球游戏源代码
  6. 合宙Luat | 得Cat.1者得天下?万物互联又春风
  7. tripwire-文件指纹
  8. BJFU_数据结构习题_218基于链式存储结构的图书信息表的最贵图书的查找
  9. OTT安卓电视盒系统发展的3种模式
  10. [win7] window 7 home basic - administrator帐号的激活