zoukankan      html  css  js  c++  java
  • 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未完待续

  • 相关阅读:
    阿里云ECS安装sqlserver,本地无法连接问题排查思路
    1433端口无法连接(sql server 数据库无法访问问题)解决思路
    开源框架 电商参考系统
    版本控制工具 Git 只下载开源项目的某个文件夹
    VUE 在idea中的运行项目
    开源框架 Java Guns 03 数据库替换为sqlite
    SQL Server 用ip地址登录 127.0.0.1
    开源框架 UI框架
    电商 电商系统汇总
    电商 平台汇总
  • 原文地址:https://www.cnblogs.com/abin30/p/10572087.html
Copyright © 2011-2022 走看看