• Abp 中 模块 加载及类型自动注入 源码学习笔记


     注意 互相关联多使用接口注册,所以可以 根据需要替换。

    始于 Startup.cs 中的 

    
    
    通过  AddApplication 扩展方法添加   Abp支持

    1
    services.AddApplication<AbpWebSiteWebModule>(options => 2 { 3 options.UseAutofac(); 4 options.Configuration.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly; 5 });

    内部,依次通过 AbpApplicationFactory、AbpApplicationWithExternalServiceProvider 注册
         return AbpApplicationFactory.Create<TStartupModule>(services, optionsAction);
         return new AbpApplicationWithExternalServiceProvider(startupModuleType, services, optionsAction);
     services.AddSingleton<IAbpApplicationWithExternalServiceProvider>(this);
    AbpApplicationWithExternalServiceProvider  同时继承自 AbpApplicationBase 

    AbpApplicationBase 构造初始化:

         services.AddSingleton<IAbpApplication>(this);
         services.AddSingleton<IModuleContainer>(this);

         services.AddCoreServices();   //添加日志、本地化、选项服务
         services.AddCoreAbpServices(this, options); //添加IModuleLoader、IAssemblyFinder、ITypeFinder ,

               给模块添加应用程序生命周期入口,允许模块在应用程序启动、关闭中执行操作。

               services.Configure<ModuleLifecycleOptions>(options =>
               {
                  options.Contributors.Add<OnPreApplicationInitializationModuleLifecycleContributor>();
                  options.Contributors.Add<OnApplicationInitializationModuleLifecycleContributor>();
                  options.Contributors.Add<OnPostApplicationInitializationModuleLifecycleContributor>();
                  options.Contributors.Add<OnApplicationShutdownModuleLifecycleContributor>();
               });

           然后调用IModuleLoader 加载模块: 加载思路是从启动模块入手,递归遍历所有依赖模块 被标记为[DependsOn]的模块

             依次执行  LoadModules -》GetDescriptors -》FillModules -》CreateModuleDescriptor -》SortByDependency  -》ConfigureServices

            最后一步是配置模块

     protected virtual void ConfigureServices(List<IAbpModuleDescriptor> modules, IServiceCollection services)
            {
                var context = new ServiceConfigurationContext(services);
                services.AddSingleton(context);
    
                foreach (var module in modules)
                {
                    if (module.Instance is AbpModule abpModule)
                    {
                        abpModule.ServiceConfigurationContext = context; //设置上下文
                    }
                }
    
                //PreConfigureServices
                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);  //加载并注册模块中的类型  如 实现这些接口的会被自动注册 ISingletonDependency ITransientDependency IScopedDependency
                        }
                    }
    
                    module.Instance.ConfigureServices(context);  //配置模块
                }
    
                //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; //清理上下文
                    }
                }
            }

      



    在  Configure 方法中初始化 AbpApplication ,

       public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
       {
           app.InitializeApplication();
       }

       请求 服务 ,并执行初始化操作

        public static void InitializeApplication([NotNull] this IApplicationBuilder app)
       {
             。。。。

             app.ApplicationServices.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Initialize(app.ApplicationServices);
        }

        开始 执行 AbpApplicationBase.InitializeModules();

    using (var scope = ServiceProvider.CreateScope())
    {
    scope.ServiceProvider
    .GetRequiredService<IModuleManager>()
    .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider));
    }

      通过 IModuleManager  初始化模块

    public void InitializeModules(ApplicationInitializationContext context)
    {
    LogListOfModules();

    foreach (var Contributor in _lifecycleContributors)
    {
    foreach (var module in _moduleContainer.Modules)
    {
    Contributor.Initialize(context, module.Instance);
    }
    }

    _logger.LogInformation("Initialized all modules.");
    }

    2、模块程序集类库注册 机制

      public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly)
            {
                foreach (var registrar in services.GetConventionalRegistrars())
                {
                    registrar.AddAssembly(services, assembly);
                }
    
                return services;
            }
    这里关键是 ConventionalRegistrarBase 用来处理那些类型是可以被注册的
    1、过滤类型 必须是 类
    var types=
    AssemblyHelper.GetAllTypes(assembly) .Where(type => type != null && type.IsClass && !type.IsAbstract && !type.IsGenericType)  
    foreach (var type in types)       {     AddType(services, type);        }
      估计本部分还在改进中
      //TODO: Make DefaultConventionalRegistrar extensible, so we can only define GetLifeTimeOrNull to contribute to the convention. This can be more performant!
    1、子类 DefaultConventionalRegistrar 重写方法
    public override void AddType(IServiceCollection services, Type type)
        (1) DisableConventionalRegistrationAttribute 如果设置了这个 属性,则跳过
    (2) 尝试取DependencyAttribute 如果有,则为生存期
    或者 GetLifeTimeOrNull取得他的生存期
    ISingletonDependency IScopedDependency ITransientDependency 直接注册,或者
    2、AbpAspNetCoreMvcConventionalRegistrar 继承自 DefaultConventionalRegistrar  重写了 GetServiceLifetimeFromClassHierarcy 方法  增加了三个接口

             if (IsController(type) ||  IsPageModel(type) ||IsViewComponent(type)){return ServiceLifetime.Transient;}

    
    
    


    private static bool IsPageModel(Type type)
    {
    return typeof(PageModel).IsAssignableFrom(type) || type.IsDefined(typeof(PageModelAttribute), true);
    }

    private static bool IsController(Type type)
    {
    return typeof(Controller).IsAssignableFrom(type) || type.IsDefined(typeof(ControllerAttribute), true);
    }

    private static bool IsViewComponent(Type type)
    {
    return typeof(ViewComponent).IsAssignableFrom(type) || type.IsDefined(typeof(ViewComponentAttribute), true);
    }



    如果都符合条件,则进行注册

        //查找这个类型暴漏的所有服务!,每一个服务根据依赖情况进行替换、添加

          foreach (var serviceType in AutoRegistrationHelper.GetExposedServices(services, type))

         //查找过程
       private static IEnumerable<Type> GetDefaultExposedServices(IServiceCollection services, Type type)
            {
                var serviceTypes = new List<Type>();
    
                serviceTypes.Add(type);
    
                foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
                {
                    var interfaceName = interfaceType.Name;
    
                    if (interfaceName.StartsWith("I"))
                    {
                        interfaceName = interfaceName.Right(interfaceName.Length - 1);
                    }
    
                    if (type.Name.EndsWith(interfaceName))
                    {
                        serviceTypes.Add(interfaceType);
                    }
                }
    
                var exposeActions = services.GetExposingActionList();
                if (exposeActions.Any())
                {
                    var args = new OnServiceExposingContext(type, serviceTypes);
                    foreach (var action in services.GetExposingActionList())
                    {
                        action(args);
                    }
                }
    
                return serviceTypes;
            }
    
    
    
     

     ----w未完待续

  • 相关阅读:
    什么是序列化
    命令执行漏洞
    sql注入总结
    npm包之merge-descriptors
    Koa路由中间件之koa-router
    TypeScript声明文件(.d.ts)的使用
    TypeScript使用的简单记录
    TypeScript的安装、使用及配置
    Node websocket简单封装
    使用docker-compose配置mysql服务
  • 原文地址:https://www.cnblogs.com/abin30/p/10572087.html
Copyright © 2020-2023  润新知