入口

//ConfigureServices
foreach (var module in Modules)
{
if (module.Instance is AbpModule abpModule)
{
if (!abpModule.SkipAutoServiceRegistration)
{
// 自动注册服务
Services.AddAssembly(module.Type.Assembly);
}
} try
{
module.Instance.ConfigureServices(context);
}
catch (Exception ex)
{
throw new AbpInitializationException($"An error occurred during {nameof(IAbpModule.ConfigureServices)} phase of the module {module.Type.AssemblyQualifiedName}. See the inner exception for details.", ex);
}
}
public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly)
{
// 遍历所有的约定注册器,进行服务注册(默认只有一个)
foreach (var registrar in services.GetConventionalRegistrars())
{
registrar.AddAssembly(services, assembly);
} return services;
}

GetConventionalRegistrars

 public static List<IConventionalRegistrar> GetConventionalRegistrars(this IServiceCollection services)
{
return GetOrCreateRegistrarList(services);
} private static ConventionalRegistrarList GetOrCreateRegistrarList(IServiceCollection services)
{
var conventionalRegistrars = services.GetSingletonInstanceOrNull<IObjectAccessor<ConventionalRegistrarList>>()?.Value;
if (conventionalRegistrars == null)
{
conventionalRegistrars = new ConventionalRegistrarList { new DefaultConventionalRegistrar() }; // 默认约定注册
services.AddObjectAccessor(conventionalRegistrars);
} return conventionalRegistrars;
}

registrar.AddAssembly(services, assembly) 相当于 DefaultConventionalRegistrar.AddAssembly。所以直接看DefaultConventionalRegistrar的AddAssembly即可。

DefaultConventionalRegistrar继承于ConventionalRegistrarBase,AddAssembly直接调用ConventionalRegistrarBase.AddAssembly。所以先看ConventionalRegistrarBase

public abstract class ConventionalRegistrarBase : IConventionalRegistrar
{
public virtual void AddAssembly(IServiceCollection services, Assembly assembly)
{
// 查找程序集内所有, 是Class,非抽象,非繁星的所有类型。
var types = AssemblyHelper
.GetAllTypes(assembly)
.Where(
type => type != null &&
type.IsClass &&
!type.IsAbstract &&
!type.IsGenericType
).ToArray(); AddTypes(services, types);
} public virtual void AddTypes(IServiceCollection services, params Type[] types)
{
foreach (var type in types)
{
AddType(services, type);
}
} public abstract void AddType(IServiceCollection services, Type type); protected virtual bool IsConventionalRegistrationDisabled(Type type)
{
return type.IsDefined(typeof(DisableConventionalRegistrationAttribute), true);
} protected virtual void TriggerServiceExposing(IServiceCollection services, Type implementationType, List<Type> serviceTypes)
{
var exposeActions = services.GetExposingActionList();
if (exposeActions.Any())
{
var args = new OnServiceExposingContext(implementationType, serviceTypes);
foreach (var action in exposeActions)
{
action(args);
}
}
}
}

AddType在子类实现,继续看DefaultConventionalRegistrar.AddType

public class DefaultConventionalRegistrar : ConventionalRegistrarBase
{
public override void AddType(IServiceCollection services, Type type)
{
// 明确禁止的,不注入。即类上加[DisableConventionalRegistration]的
if (IsConventionalRegistrationDisabled(type))
{
return;
} // 获取[Dependency]属性
var dependencyAttribute = GetDependencyAttributeOrNull(type);
// 先从Dependency获取,没找到,则从ITransientDependency,ISingletonDependency,IScopedDependency获取
var lifeTime = GetLifeTimeOrNull(type, dependencyAttribute); if (lifeTime == null)
{
return;
} // 获取暴露的服务
var exposedServiceTypes = ExposedServiceExplorer.GetExposedServices(type); // 触发服务暴露事件
TriggerServiceExposing(services, type, exposedServiceTypes); // 服务注册
foreach (var exposedServiceType in exposedServiceTypes)
{
var serviceDescriptor = CreateServiceDescriptor(
type,
exposedServiceType,
exposedServiceTypes,
lifeTime.Value
); if (dependencyAttribute?.ReplaceServices == true)
{
services.Replace(serviceDescriptor);
}
else if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
else
{
services.Add(serviceDescriptor);
}
}
} protected virtual ServiceDescriptor CreateServiceDescriptor(
Type implementationType,
Type exposingServiceType,
List<Type> allExposingServiceTypes,
ServiceLifetime lifeTime)
{
if (lifeTime.IsIn(ServiceLifetime.Singleton, ServiceLifetime.Scoped))
{
var redirectedType = GetRedirectedTypeOrNull(
implementationType,
exposingServiceType,
allExposingServiceTypes
); if (redirectedType != null)
{
return ServiceDescriptor.Describe(
exposingServiceType,
provider => provider.GetService(redirectedType),
lifeTime
);
}
} return ServiceDescriptor.Describe(
exposingServiceType,
implementationType,
lifeTime
);
} protected virtual Type GetRedirectedTypeOrNull(
Type implementationType,
Type exposingServiceType,
List<Type> allExposingServiceTypes)
{
if (allExposingServiceTypes.Count < 2)
{
return null;
} if (exposingServiceType == implementationType)
{
return null;
} if (allExposingServiceTypes.Contains(implementationType))
{
return implementationType;
} return allExposingServiceTypes.FirstOrDefault(
t => t != exposingServiceType && exposingServiceType.IsAssignableFrom(t)
);
} protected virtual DependencyAttribute GetDependencyAttributeOrNull(Type type)
{
return type.GetCustomAttribute<DependencyAttribute>(true);
} protected virtual ServiceLifetime? GetLifeTimeOrNull(Type type, [CanBeNull] DependencyAttribute dependencyAttribute)
{
return dependencyAttribute?.Lifetime ?? GetServiceLifetimeFromClassHierarcy(type);
} protected virtual ServiceLifetime? GetServiceLifetimeFromClassHierarcy(Type type)
{
if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Transient;
} if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Singleton;
} if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
{
return ServiceLifetime.Scoped;
} return null;
}
}

服务暴露

ExposedServiceExplorer

public static class ExposedServiceExplorer
{
// 默认所有以大写I开头的接口及自身
private static readonly ExposeServicesAttribute DefaultExposeServicesAttribute =
new ExposeServicesAttribute
{
IncludeDefaults = true,
IncludeSelf = true
}; public static List<Type> GetExposedServices(Type type)
{
return type
.GetCustomAttributes(true)
.OfType<IExposedServiceTypesProvider>()
.DefaultIfEmpty(DefaultExposeServicesAttribute)
.SelectMany(p => p.GetExposedServiceTypes(type))
.Distinct()
.ToList();
}
}

ExposeServicesAttribute继承IExposedServiceTypesProvider

public class ExposeServicesAttribute : Attribute, IExposedServiceTypesProvider
{
public Type[] ServiceTypes { get; } public bool IncludeDefaults { get; set; } public bool IncludeSelf { get; set; } public ExposeServicesAttribute(params Type[] serviceTypes)
{
ServiceTypes = serviceTypes ?? new Type[0];
} public Type[] GetExposedServiceTypes(Type targetType)
{
var serviceList = ServiceTypes.ToList(); if (IncludeDefaults) // 默认所有以大写I开头的接口以及自身(如果IncludeSelf=true)
{
foreach (var type in GetDefaultServices(targetType))
{
serviceList.AddIfNotContains(type);
} if (IncludeSelf)
{
serviceList.AddIfNotContains(targetType);
}
}
else if (IncludeSelf)
{
serviceList.AddIfNotContains(targetType); // 仅自身
} return serviceList.ToArray();
} // 以大写I开头的接口作为服务
private static List<Type> GetDefaultServices(Type type)
{
var serviceTypes = new List<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);
}
} return serviceTypes;
}
}

ABP源码分析 - 约定注册(3)的更多相关文章

  1. ABP源码分析 - 约定注册(2)

    比较随意,记录下过程,以便忘了以后重拾. 所谓约定注册是指不需要明确写代码注入,只需要按约定规则写服务类,框架自动完成服务注册. 例如,只要这样写,框架就会自动注册. public class Tax ...

  2. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  3. ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  4. [Abp 源码分析]三、依赖注入

    0.简要介绍 在 Abp 框架里面,无时无刻不存在依赖注入,关于依赖注入的作用与好处我就不在这里多加赘述了,网上有很多解释的教程.在 [Abp 源码分析]一.Abp 框架启动流程分析 里面已经说过,A ...

  5. [Abp 源码分析]十七、ASP.NET Core 集成

    0. 简介 整个 Abp 框架最为核心的除了 Abp 库之外,其次就是 Abp.AspNetCore 库了.虽然 Abp 本身是可以用于控制台程序的,不过那样的话 Abp 就基本没什么用,还是需要集合 ...

  6. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  7. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  8. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

  9. ABP源码分析四:Configuration

    核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...

随机推荐

  1. C/C++读取SEGY文件(三)

    SEGY IO (IBM&PC) 本文档将介绍SEGY的读取与写入过程,其中包括IBM与PC两种数据格式的转换. 程序将调用IEEE2IBM.cpp文件完成IBM与PC格式的互相转换. 新建头 ...

  2. pd.merge操作的on参数解释

    # 同时传入两个Key,此时会进行以['key1','key2']列表的形式进行对应,left的keys列表是:[['K0', 'K0'],['K0', 'K1'],['K1', 'K0'],['K2 ...

  3. 【数据库】优化SQL语言

    第1章数据模型设计 第1条:确保所有表都有主键 [1]当表缺少主键时,会出现各种问题,所有表都必须有一列(或多列)设置为主键. [2]主键应当具备的特征 唯一性,值非空,不可变,尽可能简单 [3]不要 ...

  4. 云平台将故障Pod流量下线通用思路与OpenShift操作实战

    1 写在前边 自从公司项目前年上了 OpenShift 3.9 私有云平台,更新部署程序的确变得更加容易了.但是带来了很多复杂性,运维实施人员的学习曲线也陡然上升. 上云之前:在项目没上容器云的早期, ...

  5. mavan的安装与配置

    1.下载mavan 下载路径:http://maven.apache.org/download.cgi 2.安装mavan 将下载好的压缩包解压到指定位置 3.配置系统环境变量 添加一个MAVAN_H ...

  6. .NET 6学习笔记(2)——通过Worker Service创建Windows Service

    通过Visual Studio中的Windows Service模板,我么可以创建.NET Framework版本的Windows Service,网络上对此已有详细且丰富的各路教程.但在我们升级到. ...

  7. Linux 进程打开最大文件连接数Too many open files

    首先出现这个提示的原因:应用程序打开的文件数量超过了系统设定值. 如何查看当前系统每个用户最大允许打开文件数量: [root@registry ~]# ulimit -a core file size ...

  8. 5月25日 python学习总结 HTML标签

    一.HTML简介  http://www.cnblogs.com/linhaifeng/articles/8973878.html 二.HTML标签与文档结构 http://www.cnblogs.c ...

  9. [bzoj3585] Rmq Problem / mex

    [bzoj3585] Rmq Problem / mex bzoj luogu 看上一篇博客吧,看完了这个也顺理成章会了( (没错这篇博客就是这么水) #include<cstdio> # ...

  10. 文档类型声明<!DOCTYPE html>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...