ABPvnext源码分析 (一):核心模块Abp.Core

写在前面:

ABPvnext(v2)在github开源地址为https://github.com/abpframework/abp,该项目是ABP项目基于netcore版本的第二代实现。他基于netcore3.0,相对于v1,更轻量级,面向微服务等现代网络架构,是学习netcore,学习架构设计的很好的素材。
本系列记录ABPvnext源码学习的详细内容,基于的版本是v1.0正式版。

核心模块(Core模块):ABP的Core模块为Volo.Abp.Core程序包,可以通过nuget安装使用,大家也可以在github查看其源码(framework/src/Volo.Abp.Core)。Core模块整体看来分为两大部分。一部分为一些基础的帮助函数,大部分为无依赖的独立的扩展方法。由于这部分代码相互牵扯很少,相信读者很容易看懂,本篇直接忽略。本篇关注的是另一部分, DI封装以及相关的一些基础功能(这块代码主要在framework/src/Volo.Abp.Core/Volo/)。
Core模块DI相关部分主要是实现了模块管理功能,其主要参考了Autofac模块管理的实现。我想之所以重新实现一遍没有直接依赖Autofac是为了和具体的DI依赖库相隔离,做一层中间层(ABP的DI实现)。代码的其他部分依赖于中间层而不依赖于Autofac,这样可以基于不同的DI层或者就使用aspnetcore默认的DI层。

ABP的Core模块提供了哪些具体的核心功能:
(我们约定把DI中进行注册的类别叫服务,获取的服务实例叫组件)
1.核心服务注册: 包括core核心服务及Abp核心服务注册。 core核心服务包含日志服务,国际化服务以及选项服务;Abp核心服务主要包含的模块管理相关的一些基础服务
2.module注册:解决方案中每个项目添加一个abp module类,其中进行该项目的一些服务配置,模块间依赖配置(模块间依赖基本和项目间依赖一致)
3.规约服务注册(Dependency注解,ISingletonDependency,ITransientDependency,IScopedDependency接口,ExposeServices注解)
4.模块加载 加载模块并按照依赖关系排序,依次执行他们的生命周期方法。
5.动态代理功能: Core模块定义了ABP中代理的一些基础接口,这里并没有相关的具体代理实现依赖。ABP提供了一个具体依赖的实现:在Volo.Abp.Autofac及Volp.Abp.CastleCore包中,上层包中主要使用的是这个实现。

在我们分析Core源码时,如果能把这几块核心功能的相关代码搞清楚,整个Abp.Core的实现也就没有什么难点了。
另外,Core项目可以单独使用。我们查看Volo.Abp.Core的包依赖,发现并没有额外的三方依赖。我们完全可以把Core看成Autofac一个阉割简易的但完全足够使用的版本。读懂Core的源码,抛弃Autofac的一些不常用的复杂的功能,直接使用Abp.Core做为DI库,本身也是个不错的选择。

正菜开始:

首先我们从TestCase中找一段abp的使用起手式,如下:

     [Fact]
        public void Should_Use_Empty_ConfigurationRoot_By_Default()
        {
            using (var application = AbpApplicationFactory.Create<IndependentEmptyModule>()) //ABP模块(数据,new 没有行为)=>ABP Application  new的时候完成相关服务注册
            {
                var services = application.Services;
                var configuration1 = application.Services.GetConfiguration();
                configuration1.ShouldNotBeNull();

                application.Initialize();// 初始化模块, 模块服务已经注入DI,这里执行模块的INIT HOOK方法
                var configuration2 = ResolveConfiguration(application);

                configuration2.ShouldBe(configuration1);
            }
        }

 通过 AbpApplicationFactory 获取  abpApplication,其Services属性就是注册了各种初始服务的seviceCollection。   abpApplication.Initialize() 可以执行app的初始化工作。

我们继续跟踪这个AbpApplicationFactory.Create<IndependentEmptyModule>(),其内部调用的是

    internal AbpApplicationBase( //构造的时候就会注册相关服务,加载各个abp模块 
            [NotNull] Type startupModuleType,
            [NotNull] IServiceCollection services, //services是构造时传入的 
            [CanBeNull] Action<AbpApplicationCreationOptions> optionsAction)
        {
            Check.NotNull(startupModuleType, nameof(startupModuleType));
            Check.NotNull(services, nameof(services));

            StartupModuleType = startupModuleType;
            Services = services;

            services.TryAddObjectAccessor<IServiceProvider>();  //ObjectAccessor采用头插法,放入其中的查找较快。 AddObjectAccessor一注册注册一对儿:ObjectAccessor;IObjectAccessor

            var options = new AbpApplicationCreationOptions(services); //new的一个空对象 这和下面一句是一个经典套路
            optionsAction?.Invoke(options);  //调用Action

            services.AddSingleton<IAbpApplication>(this); //两个服务IAbpApplication,IModuleContainer都是AbpApplicationBase对象本身
            services.AddSingleton<IModuleContainer>(this);

            services.AddCoreServices();//核心基本服务  Options  Logging Localization
            services.AddCoreAbpServices(this, options); //ABP核心模块 主要是模块系统相关组件。

            Modules = LoadModules(services, options); //加载模块并按照依赖关系排序,依次执行他们的生命周期方法。 IMPORTANT
        }

参数services是一个new的空的 ServiceCollection。

里面重要的方法调用是

services.AddCoreAbpServices(this, options);
LoadModules(services, options);

我们分别展开来看:

internal static void AddCoreAbpServices(this IServiceCollection services, //添加ABP相关服务
            IAbpApplication abpApplication, //需要这个做输入IAbpApplication代表ABP配置
            AbpApplicationCreationOptions applicationCreationOptions) //读取Configuration配置
        {
            var moduleLoader = new ModuleLoader();  //几个关键类型ModuleLoader, AssemblyFinder,TypeFinder
            var assemblyFinder = new AssemblyFinder(abpApplication);  //StartupModules=>Modules=>Assemblies
            var typeFinder = new TypeFinder(assemblyFinder);  //封装了所有程序集中所有的Types

            if (!services.IsAdded<IConfiguration>()) // 没IConfiguration 服务的话
            {
                services.ReplaceConfiguration(
                    ConfigurationHelper.BuildConfiguration(  //生成Configuration对象并注册(默认规则appsetting.json环境变量,命令行参数等)
                        applicationCreationOptions.Configuration
                    )
                );
            }

            services.TryAddSingleton<IModuleLoader>(moduleLoader); //moduleLoader有装载方法
            services.TryAddSingleton<IAssemblyFinder>(assemblyFinder);
            services.TryAddSingleton<ITypeFinder>(typeFinder);

            services.AddAssemblyOf<IAbpApplication>(); //添加Volo.Abp.Core程序集(基于约定方式的,注册程序集中services)IMPORTANT

            services.Configure<AbpModuleLifecycleOptions>(options =>  //配置模块声明周期的HOOKS
            {
                options.Contributors.Add<OnPreApplicationInitializationModuleLifecycleContributor>();
                options.Contributors.Add<OnApplicationInitializationModuleLifecycleContributor>();
                options.Contributors.Add<OnPostApplicationInitializationModuleLifecycleContributor>();
                options.Contributors.Add<OnApplicationShutdownModuleLifecycleContributor>();
            });

        }

services.AddCoreAbpServices(this, options)中先是注册默认的IConfiguration服务(默认行为先读文件再读UserSecrets再读环境变量再读命令行变量,同名的后读的覆盖先读的)

然后添加了IModuleLoader,IAssemblyFinder,ITypeFinder服务。这3个服务封是用来装查询项目以及依赖项目中定义的各种Type的方法的。其原理是通过启动模块StartupModules的依赖关系找到所有的AbpModules,每个AbpModule对应一个Assemblies,然后在每个Assemblies通过反射找到所有定义的Type。

services.AddAssemblyOf<IAbpApplication>(); 添加Volo.Abp.Core程序集(基于约定方式的,注册程序集中services)。他对程序集中每一个Type类型调用规约注册器判断是否注册为服务以及如何注册为服务。
默认实现的规约注册器DefaultConventionalRegistrar是通过识别Dependency注解,ISingletonDependency,ITransientDependency,IScopedDependency接口,ExposeServices注解等判断如何进行服务注册行为。

最后是配置声明模块周期选项,用于模块初始化或关闭时添加钩子行为。LoadModules(services, options)使用默认的ModuleLoader实现加载模块并按照依赖关系排序,依次执行他们的生命周期方法。

        public IAbpModuleDescriptor[] LoadModules(
            IServiceCollection services,
            Type startupModuleType,
            PlugInSourceList plugInSources)
        {
            Check.NotNull(services, nameof(services));
            Check.NotNull(startupModuleType, nameof(startupModuleType));
            Check.NotNull(plugInSources, nameof(plugInSources));

            var modules = GetDescriptors(services, startupModuleType, plugInSources);

            modules = SortByDependency(modules, startupModuleType);//排下序,最内层依赖在最前面
            ConfigureServices(modules, services); //核心方法,执行每个模块(包括注册模块所在的约定服务以及,执行模块的各个回调) IMPORTANT 

            return modules.ToArray();
        }

其中ConfigureServices如下:

       protected virtual void ConfigureServices(List<IAbpModuleDescriptor> modules, IServiceCollection services) //可以看成是执行一个个模块 执行顺序:1.执行所有的preConfigure 2.执行每一个模块(先注册该模块约定服务,再执行configureService)3。执行所有的postConfigure
        {
            var context = new ServiceConfigurationContext(services);
            services.AddSingleton(context); //DI注册ServiceConfigurationContext

            foreach (var module in modules)
            {
                if (module.Instance is AbpModule abpModule)
                {
                    abpModule.ServiceConfigurationContext = context;   //装载前设置abpModule.ServiceConfigurationContext
                }
            }

            //PreConfigureServices PreConfigureServices,ConfigureServices,PostConfigureServices只是调用模块HOOK先后顺序不同, 所有PreConfigureServices=>所有ConfigureServices=>所有PostConfigureServices
            foreach (var module in modules.Where(m => m.Instance is IPreConfigureServices))
            {
                ((IPreConfigureServices)module.Instance).PreConfigureServices(context);
            }

            //ConfigureServices
            foreach (var module in modules)
            {
                if (module.Instance is AbpModule abpModule)
                {
                    if (!abpModule.SkipAutoServiceRegistration)
                    {
                        services.AddAssembly(module.Type.Assembly);  //注册模块所在程序集中的约定服务
                    }
                }

                module.Instance.ConfigureServices(context);  //先注册所有的约定服务,再执行模块ConfigureServices方法
            }

            //PostConfigureServices
            foreach (var module in modules.Where(m => m.Instance is IPostConfigureServices))
            {
                ((IPostConfigureServices)module.Instance).PostConfigureServices(context);
            }

            foreach (var module in modules)
            {
                if (module.Instance is AbpModule abpModule)
                {
                    abpModule.ServiceConfigurationContext = null; //装载后再清空abpModule.ServiceConfigurationContext
                }
            }
        }

由代码我们可以看出,项目中多个abpModule情况下, 先根据依赖关系依次执行所有模块的PreConfigureServices钩子方法;再对每一个模块先注册模块所在程序集中的约定服务,再

执行ConfigureServices;最后再依次执行所有模块PostConfigureServices方法。 这就是模块加载生命周期的钩子函数调用顺序。

 到此,abpApplication的创建就讲完了,我们回忆一下:abpApplication的创建是以启动模块为参数Create创建出来的。在创建的过程完成了IConfigure的注册, Abp模块的注册加载,模块中各个约定服务的注册,模块声明周期钩子函数的执行等操作。最后回到开始时TestCase的例子,abpApplication调用Initialize()执行abp应用的声明周期钩子行为(应用初始化行为)。

  public void Initialize()
        {
            ServiceScope = Services.BuildServiceProviderFromFactory().CreateScope();// 创建ServiceProvider创建子ServiceProvider
            SetServiceProvider(ServiceScope.ServiceProvider);
            
            InitializeModules();
        }

通过BuildServiceProviderFromFactory()创建根ServiceProvider。

    public static IServiceProvider BuildServiceProviderFromFactory([NotNull] this IServiceCollection services)  //核心方法 IMPORTANT 从services中找serviceproviderfactory    services是注册信息   serviceProvider可以理解是services的代理 封装了services;另外,serviceProvider有层次关系而services是层级共享的
        {
            Check.NotNull(services, nameof(services));

            foreach (var service in services) //遍历services   注册时可能是 AaaServiceProviderFactory<Bbb>这种,所以不能直接GetService
            {
                
                var factoryInterface = service.ServiceType;
                if (factoryInterface == null || !factoryInterface.IsGenericType  ||
                    factoryInterface.GetTypeInfo().GetGenericTypeDefinition() != typeof(IServiceProviderFactory<>))
                {
                    continue;
                }

                var containerBuilderType = factoryInterface.GenericTypeArguments[0]; //获得 Bbb   Bbb是TContainerBuilder
                return (IServiceProvider)typeof(ServiceCollectionCommonExtensions)  //hack,通过反射调用泛型方法
                    .GetTypeInfo()
                    .GetMethods()
                    .Single(m => m.Name == nameof(BuildServiceProviderFromFactory) && m.IsGenericMethod)
                    .MakeGenericMethod(containerBuilderType)
                    .Invoke(null, new object[] { services, null });  //会调用 services.GetSingletonInstanceOrNull<IServiceProviderFactory<TContainerBuilder>>();
            }

            return services.BuildServiceProvider();//找不到的话使用默认实现
        }

        public static IServiceProvider BuildServiceProviderFromFactory<TContainerBuilder>([NotNull] this IServiceCollection services, Action<TContainerBuilder> builderAction = null)
        {
            Check.NotNull(services, nameof(services));

            var serviceProviderFactory = services.GetSingletonInstanceOrNull<IServiceProviderFactory<TContainerBuilder>>();  //获取工厂类的对象
            if (serviceProviderFactory == null)
            {
                throw new AbpException($"Could not find {typeof(IServiceProviderFactory<TContainerBuilder>).FullName} in {services}.");
            }

            var builder = serviceProviderFactory.CreateBuilder(services);// ABP默认使用的是Autofac的IServiceProviderFactory实现ContainerBuilder,还是基于之前的services
            builderAction?.Invoke(builder);
            return serviceProviderFactory.CreateServiceProvider(builder); //使用工厂类对象生成ServiceProvider
        }

从上面代码看出 services已注册IServiceProviderFactory<TContainerBuilder>,则使用该组件进行初始化abpApplication,否则根据services生成一个netcore3默认的ServiceProvider初始化abpApplication。

 abpCore部分的源码实现如上所述,如果要结合动态代理以及mvc使用,请关注后续的课程。

 
 
原文地址:https://www.cnblogs.com/yilianhuaixiao/p/11791100.html