• 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使用,请关注后续的课程。

     
     
  • 相关阅读:
    Java实验项目六——使用DAO模式实现对职工表的操作
    Java实验项目三——职工类对象数组按照职工生日排序
    Java实验项目三——编程实现Person类,学生类的设计及其继承关系
    Java实验项目三——平面图形和立体图形抽象类
    javax.naming.NoInitialContextException:Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
    对实体 "useSSL" 的引用必须以 ';' 分隔符结尾。
    MATLAB自定义配置
    POJ 2976 Dropping tests(最大化平均值 or 01整数规划)
    POJ3273 Monthly Expense
    POJ3258 River Hopscotch
  • 原文地址:https://www.cnblogs.com/yilianhuaixiao/p/11791100.html
Copyright © 2020-2023  润新知