设为首页 加入收藏

TOP

[Abp vNext 源码分析] - 3. 依赖注入与拦截器(一)
2019-09-17 18:45:30 】 浏览:128
Tags:Abp vNext 源码 分析 依赖 注入 拦截

一、简要说明

ABP vNext 框架在使用依赖注入服务的时候,是直接使用的微软提供的 Microsoft.Extensions.DependencyInjection 包。这里与原来的 ABP 框架就不一样了,原来的 ABP 框架还需要抽象出来一个 IIocManager 用来管理整个 IoC 容器,现在则直接操作 IServiceCollectionIServiceProvider 进行组件的注册/解析。

这里需要注意的是,虽然现在的依赖注入服务是使用微软官方那一套库进行操作,但是 ABP vNext 还是为我们提供了组件自动注册、拦截器这些基础功能。

二、源码分析

2.1 组件自动注册

ABP vNext 仍然在其 Core 库为我们提供了三种接口,即 ISingletonDependencyITransientDependencyIScopedDependency 接口,方便我们的类型/组件自动注册,这三种接口分别对应了对象的 单例瞬时范围 生命周期。只要任何类型/接口实现了以上任意接口,ABP vNext 就会在系统启动时候,将这些对象注册到 IoC 容器当中。

那么究竟是在什么时候呢?回顾上一章的模块系统的文章,在模块系统调用模块的 ConfigureService() 的时候,就会有一个 services.AddAssembly(module.Type.Assembly) ,他会将模块的所属的程序集传入。

public class ModuleLoader : IModuleLoader
{
    // ... 其他代码
    protected virtual void ConfigureServices(List<IAbpModuleDescriptor> modules, IServiceCollection services)
    {
        // ... 其他代码
        //ConfigureServices
        foreach (var module in modules)
        {
            if (module.Instance is AbpModule abpModule)
            {
                // 是否跳过服务的自动注册,默认为 false。
                if (!abpModule.SkipAutoServiceRegistration)
                {
                    services.AddAssembly(module.Type.Assembly);
                }
            }

            module.Instance.ConfigureServices(context);
        }
        // ... 其他代码
    }
    // ... 其他代码
}

看来核心就在于这个 AddAssembly() 扩展方法了,跳转到方法的内部,发现真正干事的是 IConventionalRegistrar 对象,暂且称之为规约注册器,而且我们可以拥有多个规约注册器,你可以自己实现自动注册规则。

public static IServiceCollection AddAssembly(this IServiceCollection services, Assembly assembly)
{
    // 获得所有规约注册器,然后调用规约注册器的 AddAssmbly 方法注册类型。
    foreach (var registrar in services.GetConventionalRegistrars())
    {
        registrar.AddAssembly(services, assembly);
    }

    return services;
}

该接口定义了三个方法,支持传入程序集、类型数组、具体类型,他们的默认实现都在抽象类 ConventionalRegistrarBase 当中。

public interface IConventionalRegistrar
{
    void AddAssembly(IServiceCollection services, Assembly assembly);

    void AddTypes(IServiceCollection services, params Type[] types);

    void AddType(IServiceCollection services, Type type);
}

抽象类当中的实现也非常简单,他们最终都是调用的 AddType() 方法来将类型注册到 IServiceCollection 当中的。

public abstract class ConventionalRegistrarBase : IConventionalRegistrar
{
    public virtual void AddAssembly(IServiceCollection services, Assembly assembly)
    {
        // 获得程序集内的所有类型,过滤掉抽象类和泛型类型。
        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);
}

所以我们的重点就在于 AddType() 方法,ABP vNext 框架默认的规约注册器叫做 DefaultConventionalRegistrar,跳转到其定义可以发现在其内部,除了对三种生命周期接口处理之外,如果类型使用了 DependencyAttribute 特性,也会根据该特性的参数配置进行不同的注册逻辑。

public override void AddType(IServiceCollection services, Type type)
{
    // 判断类型是否标注了 DisableConventionalRegistration 特性,如果有标注,则跳过。
    if (IsConventionalRegistrationDisabled(type))
    {
        return;
    }

    // 获得 Dependency 特性,如果没有则返回 null。
    var dependencyAttribute = GetDependencyAttributeOrNull(type);
    // 优先使用 Dependency 特性所指定的生命周期,如果不存在则根据 type 实现的接口确定生命周期。
    var lifeTime = GetLifeTimeOrNull(type, dependencyAttribute);

    if (lifeTime == null)
    {
        return;
    }

    // 获得等待注册的类型定义,类型的定义优先使用 ExposeServices 特性指定的类型,如果没有则使用
    // 类型当中接口以 I 开始,后面为实现类型名称的接口。
    foreach (var serviceType in AutoRe
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇本地Git仓库和Github仓库的关联 下一篇Asp .Net core 2 学习笔记(3) —..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目