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

始于 Startup.cs 中的 


通过  AddApplication 扩展方法添加   Abp支持
1           services.AddApplication<AbpWebSiteWebModule>(options =>
{
options.UseAutofac();
options.Configuration.UserSecretsAssembly = typeof(AbpWebSiteWebModule).Assembly;
}); 内部,依次通过 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 - );
} 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未完待续

Abp 中 模块 加载及类型自动注入 源码学习笔记的更多相关文章

  1. ES6中模块加载出现的问题

    1.如何在浏览器中import模块 在使用模块加载时不同浏览器有不同的行为 使用 import 加载模块时,需要把script标签的type属性改为module.此时Firefox浏览器支持impor ...

  2. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  3. SparkConf加载与SparkContext创建(源码阅读一)

    即日起开始spark源码阅读之旅,这个过程是相当痛苦的,也许有大量的看不懂,但是每天一个方法,一点点看,相信总归会有极大地提高的.那么下面开始: 创建sparkConf对象,那么究竟它干了什么了类,从 ...

  4. SparkConf加载与SparkContext创建(源码阅读四)

    sparkContext创建还没完呢,紧接着前两天,我们继续探索..作死... 紧接着前几天我们继续SparkContext的创建: 接下来从这里我们可以看到,spark开始加载hadoop的配置信息 ...

  5. SparkConf加载与SparkContext创建(源码阅读二)

    紧接着昨天,我们继续开搞了啊.. 1.下面,开始创建BroadcastManager,就是传说中的广播变量管理器.BroadcastManager用于将配置信息和序列化后的RDD.Job以及Shuff ...

  6. ehcache加载配置文件ehcache.xml的源码

    package net.sf.ehcache.config; public final class ConfigurationFactory { public static Configuration ...

  7. flutter源码学习笔记-图片加载流程

    本文基于1.12.13+hotfix.8版本源码分析. 0.大纲 Image ImageProvider 图片数据加载 ImageStream.ImageStreamCompleter 缓存池 Pai ...

  8. Spring源码阅读 之 配置的加载(希望有喜欢源码的朋友一起交流)

    想写Spring的源码方面的东西想了好久了,之前花了一段时间学习了SpringCloud,现在总算对SpringCloud有了一个大概的了解,从今天开始好好读一篇Spring的源码,结合书本跟网上的一 ...

  9. jQuery+Ajax滚屏异步加载数据实现(附源码)

    一.CSS样式 body { font:12px/1.0em Microsoft Yahei; line-height:1.6em; background:#fff; line-height:1.2e ...

随机推荐

  1. 数据库session立即生效(64---8192) SCOPE参数

    SCOPE=MEMORY|SPFILE|BOTH 指示了修改参数时的“作用域”: SCOPE=MEMORY :只在实例中修改,重启数据库后此次修改失效. SCOPE=SPFILE :只修改SPFILE ...

  2. Spring boot 配置https 实现java通过https接口访问

    近来公司需要搭建一个https的服务器来调试接口(服务器用的spring boot框架),刚开始接触就是一顿百度,最后发现互联网认可的https安全链接的证书需要去CA认证机构申请,由于是调试阶段就采 ...

  3. ORACLE 12c RAC的常用管理命令

    ORACLE 12c RAC的常用管理命令 一.查询 1.RAC查询 1.1.查询节点 [grid@swnode1 ~]$ su - grid [grid@swnode1 ~]$ /u01/app/1 ...

  4. iOS绘制坐标图,折线图-Swift

    坐标图,经常会在各种各样的App中使用,最常用的一种坐标图就是折线图,根据给定的点绘制出对应的坐标图是最基本的需求.由于本人的项目需要使用折线图,第一反应就是搜索已经存在的解决方案,因为这种需求应该很 ...

  5. NOIP 2017 宝藏 - 动态规划

    题目传送门 传送门 题目大意 (家喻户晓的题目不需要题目大意) 设$f_{d, s}$表示当前树的深度为$d$,与第一个打通的点连通的点集为$s$. 每次转移的时候不考虑实际的深度,深度都当做$d$, ...

  6. IDEA 初建Spring项目(Hello Spring)

    新建项目 在文件夹中建立一个项目文件 打开项目 打开IDEA,点击Open,根据所建项目路径找到该项目 依赖注入 点击项目名右键,点击new,点击file,创建pom.xml 内容为: <pro ...

  7. Spring Boot 2 整合Swagger简单入门

    Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件. 1.pom.xml添加配置 可以到http://mvnrepository.com上搜索springfox,便可以看到Sp ...

  8. CAS工程用redis集群存储票据ticket Spring整合

    maven jar包版本: <dependency> <groupId>redis.clients</groupId> <artifactId>jedi ...

  9. mc面试题记录

    1.linux 查看磁盘空间 df -hl 2.根目录下有哪些文件及其作用 3.查找/tmp下的文件内容含有abc的命令 grep -rn "abc" /tmp4.linux下的s ...

  10. centos7 基础命令

    一: linux基础 (1) 查看服务器的IP信息 ip add showifconfig (2) 操作网卡命令(重启网络和启用网卡) systemctl restart networksystemc ...