入口

//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. Laravel-Auth认证

    1.建立数据表 admins 2.找到config下的auth.php 文件,加入如下代码 <?php return [ /* |-------------------------------- ...

  2. 一比一还原axios源码(四)—— Axios类

    axios源码的分析,到目前为止,算上第0章已经四章了,但是实际上,还都没有进入axios真正的主线,我们来简单回顾下.最开始我们构建了get请求,写了重要的buildURL方法,然后我们处理请求体请 ...

  3. LGP4199题解

    因为没有简化题意一直没去做,直到今天讲这道题才口胡出来 要求对称,很明显这样一个"子序列"的对称中心只可能有一个,那么先枚举这个对称中心. 然后我们需要判断两个位置是否相同.看上去 ...

  4. 新建SpringBoot项目报错

    新建一个Springboot项目时,当勾选了SQL相关的依赖(如引入了jpa 或MyBatis依赖),直接启动项目时报错 原因:没有配置数据库相关的属性,如 url driver 等 解决办法:在ap ...

  5. 基于python 实现KNN 算法

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/11/7 14:50 # @Author : gylhaut # @Site ...

  6. docker 部署mysql tomcat时 在root@localhost~下——-——docker exec -it 容器名 /bin/bash 报错

    在docker部署mysql时 报错 找不到 容器不自动启动  , docker start 容器名  也没有效果 多次尝试发现 原因是创建容器时在 下面创建的 更改为下创建 问题解决

  7. 修改vue的url

    1.修改router的index.js文件,增加base url的配置 2.修改config的index.js文件. bulid的index,assetsRoots和assetsPublicPath的 ...

  8. 后门及持久化访问4----Com组件劫持

    代码及原理介绍 COM是Component Object Model(组件对象模型)的缩写,COM组件由DLL和EXE形式发布的可执行代码所组成.每个COM组件都有一个CLSID,这个CLSID是注册 ...

  9. 内网代理工具--reGeorg

    一.简介 reGeorg是reDuh的继承者,利用了会话层的socks5协议,效率更高结合Proxifier使用 Proxifier是一款功能非常强大的socks5客户端,可以让不支持通过代理服务器工 ...

  10. phpcms 2008 变量覆盖漏洞

    一. 启动环境 1.双击运行桌面phpstudy.exe软件 2.点击启动按钮,启动服务器环境 二.代码审计 1.双击启动桌面Seay源代码审计系统软件 3.点击新建项目按钮,弹出对画框中选择(C:\ ...