ABP依赖注入

介绍

熟悉Asp.Net Core的都知道,无处可见的依赖注入,可以说是核心.我们的ABP框架也是,依赖注入随处可见.
ABP中默认的依赖注入容器是Castle windsor,在使用ABP后,会在Startup执行过程中默认替换掉.Net Core自带的容器.
ABP默认在它外面又包装了一层.IocManager,为什么要在封装一层呢?. 下面再说

类关系图

类关系图

分析

IocManager基本实现

IIocManager是继承自IIocRegistrarIIocResolver,其中 IIocRegistrar 提供了服务注册的功能,
IIocResolver则提供了从容器中获取已注册的服务。IocManager是IIocManager的实现.

public interface IIocManager : IIocRegistrar, IIocResolver, IDisposable
{
    IWindsorContainer IocContainer { get; }

    new bool IsRegistered(Type type);

    new bool IsRegistered<T>();
}

IIocManager中封装了IWindsorContainer,为什么要封装呢。其实主要是为了能够快速替换其他DI框架而不影响代码

public class IocManager : IIocManager
{
    // Singletone instance for Castle ProxyGenerator.
    private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator();
    /// <summary>
    /// The Singleton instance.
    /// </summary>
    public static IocManager Instance { get; private set; }
    /// <summary>
    /// Reference to the Castle Windsor Container.
    /// </summary>
    public IWindsorContainer IocContainer { get; private set; }
    static IocManager()
    {
        Instance = new IocManager();
    }
    public IocManager()
    {
        IocContainer = CreateContainer();
        _conventionalRegistrars = new List<IConventionalDependencyRegistrar>();

        //Register self!
        IocContainer.Register(
            Component
                .For<IocManager, IIocManager, IIocRegistrar, IIocResolver>()
                .Instance(this)
        );
    }
    protected virtual IWindsorContainer CreateContainer()
    {
        return new WindsorContainer(new DefaultProxyFactory(ProxyGeneratorInstance));
    }
    public void Register<TType>(DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) where TType : class
    {
        IocContainer.Register(ApplyLifestyle(Component.For<TType>(), lifeStyle));
    }
}

可以看到我们在调用IocManager.Instance的时候会执行静态构造函数,接着会创建一个WindsorContainer容器
其中Register方法在内部,也是调用的WindsorContainer的注册方法.

IConventionalDependencyRegistrar

这是约定注入,也有说是规约注入,可以看到,在类图中,它有4个默认的实现.
先看看BasicConventionalRegistrar

public class BasicConventionalRegistrar : IConventionalDependencyRegistrar
{
    public void RegisterAssembly(IConventionalRegistrationContext context)
    {
        //Transient
        context.IocManager.IocContainer.Register(
            Classes.FromAssembly(context.Assembly)
                .IncludeNonPublicTypes()
                .BasedOn<ITransientDependency>()
                .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                .WithService.Self()
                .WithService.DefaultInterfaces()
                .LifestyleTransient()
            );

        //Singleton
        context.IocManager.IocContainer.Register(
            Classes.FromAssembly(context.Assembly)
                .IncludeNonPublicTypes()
                .BasedOn<ISingletonDependency>()
                .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                .WithService.Self()
                .WithService.DefaultInterfaces()
                .LifestyleSingleton()
            );

        //Windsor Interceptors
        context.IocManager.IocContainer.Register(
            Classes.FromAssembly(context.Assembly)
                .IncludeNonPublicTypes()
                .BasedOn<IInterceptor>()
                .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                .WithService.Self()
                .LifestyleTransient()
            );
    }
}

调用了Register方法注册了 我们实现了ISingletonDependencyITransientDependency的服务.
以及实现了IInterceptor的拦截器.
ISingletonDependencyITransientDependency都是标记接口,代表了服务以不同的生命周期注册.
如果对生命周期的实现,以及如何自动注入,感兴趣的话,可以参考我个人的简易版框架(模拟Asp.net Core自带DI的实现方式)
在 IocManager中其实有个List集合字段 _conventionalRegistrars.

private readonly List<IConventionalDependencyRegistrar> _conventionalRegistrars;

这个List存放已经有的规约注册器.那么是什么时候加进去的呢?

public sealed class AbpKernelModule : AbpModule
{
    public override void PreInitialize()
    {
        IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());
    }
}

可以看到,是在AbpKernelModule 也就是第一个模块中的预初始化方法中调用IocManager.AddConventionalRegistrar方法添加的
其中核心模块的初始化方法还调用了IocManager.RegisterAssemblyByConvention注册服务, 一般每个模块都会在初始化方法中执行RegisterAssemblyByConvention方法,注册所有符合约定的服务组件.

public void RegisterAssemblyByConvention(Assembly assembly)
{
    RegisterAssemblyByConvention(assembly, new ConventionalRegistrationConfig());
}
public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config)
{
    var context = new ConventionalRegistrationContext(assembly, this, config);

    foreach (var registerer in _conventionalRegistrars)
    {
        registerer.RegisterAssembly(context);
    }

    if (config.InstallInstallers)
    {
        IocContainer.Install(FromAssembly.Instance(assembly));
    }
}

以及 每次调用RegisterAssemblyByConvention方法时,都会遍历规约注册器集合,调用里面每个注册器的RegisterAssembly方法
其中重载方法中的入参有个ConventionalRegistrationConfig,这个对象内部是这样的。

public class ConventionalRegistrationConfig : DictionaryBasedConfig
{
    public bool InstallInstallers { get; set; }

    public ConventionalRegistrationConfig()
    {
        InstallInstallers = true;
    }
}

里面就一个bool类型的属性,默认设置为了True.

if (config.InstallInstallers)
{
    IocContainer.Install(FromAssembly.Instance(assembly));
}

也就是说这里默认是true 会执行 IocContainer.Install(FromAssembly.Instance(assembly));
这里的话会扫码你当前程序集.实现了 IWindsorInstaller接口的实现类,这里面会批量执行所有Installer的intall方法
通常就是批量注册一些服务.例如AbpCoreInstaller这里面注册了一些ABP默认的服务. . 且是在AbpBootstraper初始化方法中执行的.

IocManager.IocContainer.Install(new AbpCoreInstaller());

IocManager初始化过程

根据引用可以追溯到AbpBootStrap的构造函数中

private AbpBootstrapper([NotNull] Type startupModule, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
{
    Check.NotNull(startupModule, nameof(startupModule));

    var options = new AbpBootstrapperOptions();
    optionsAction?.Invoke(options);

    if (!typeof(AbpModule).GetTypeInfo().IsAssignableFrom(startupModule))
    {
        throw new ArgumentException($"{nameof(startupModule)} should be derived from {nameof(AbpModule)}.");
    }

    StartupModule = startupModule;

    IocManager = options.IocManager;
    PlugInSources = options.PlugInSources;

    _logger = NullLogger.Instance;

    if (!options.DisableAllInterceptors)
    {
        AddInterceptorRegistrars();
    }
}

可以看到有个AbpBootstrapperOptions这个对象的构造函数中直接调用了 IocManager = Abp.Dependency.IocManager.Instance
这里会创建IocManager.然后调用注册方法把自己注入进容器,这样其他服务组件就可以使用了.
例如在asp.net core的startup类中调用的AddABP方法.

public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
    where TStartupModule : AbpModule
{
    var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);

    ConfigureAspNetCore(services, abpBootstrapper.IocManager);

    return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
}

这里返回的就是刚才创建的IocManager.

初始化流程

posted @ 2019-01-16 14:46  KotobukiTsumugi  阅读(1638)  评论(0编辑  收藏  举报