入口

//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. python 程序小练习

    print("Type integers,each followed by Enter; or just Enter to finish") total = 0 count = 0 ...

  2. 分布式锁用Redis与Zookeeper的使用

    为什么用分布式锁?   在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会 ...

  3. 4.监控Redis--单节点

    prometheus监控redis需要用到redis_exporter. redis_exporter 项目地址:https://github.com/oliver006/redis_exporter ...

  4. Linux巡检检查项

    不定时更新...... 1)服务器 1.1 SELINUX检查(sestatus) 1.2 资源限制检查(ulimit -a) 1.3 最近登录(last) 1.4 操作系统版本(cat /etc/r ...

  5. 09自动售货机综设实验(含按键消抖,led和状态机)

    一设计功能 1.上次状态机的练习 2这次自动售货机综设 (一)对比两次的售货机 上次售货机的关键是画出状态转移图.明确输入分几种,输出是啥,有哪些状态.如下图所示 (二)系统或综合设计的经验: 既然这 ...

  6. 在Unity中用UGUI制作可输入下拉框

    Unity中UGUI制作可输入下拉框 目录 Unity中UGUI制作可输入下拉框 前言 组件分析 制作流程 总结 前言 在搜索引擎以及一些网页中我们常常可以看见这样一种UI控件,看上去是一个输入框,在 ...

  7. Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)

    创建和分布表 要创建分布式表,您需要首先定义表 schema. 为此,您可以使用 CREATE TABLE 语句定义一个表,就像使用常规 PostgreSQL 表一样. CREATE TABLE ht ...

  8. 什么是GUI?

    图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面.图形用户界面是一种人与计算机通信的界面显示格式,允许用户使用鼠 ...

  9. 创建自定义ClassLoader,绕过双亲委派

    1.什么是类加载 通过javac将.java文件编译成.class字节码文件后,则需要将.class加载到JVM中运行,哪么是谁将.class加载到JVM的呢?那就是类加载器啦. 2.类加载器类型 B ...

  10. ZooKeeper 面试题?

    ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群 中各个节点的状态根据节点提交的反馈进行下一步合理操作.最终,将简单易用 的接口和性能高效.功能稳定的系统提供给用户. ...