天天看点

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

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

简单的WebAPI DEMO

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

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

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();

        }
    }
}

           

最后调试运行成功:

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

思考

1.以前我们需要如下DI

现在ABP是通过

那是在什么时候被调用的呢?

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.创建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 :

/// <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创建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));
                        }
                    )
                )
            );
        }
           

app.UseAbp

通过前面的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()看,前面都是一些相关的初始化,最后的是重点,会对我们定义模块依赖进行注册:

/// <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)
        {
            //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()
                );
        }