zoukankan      html  css  js  c++  java
  • 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.

    初始化流程

  • 相关阅读:
    Bluedroid与BluZ,蓝牙测试方法的变动(基于bludroid和BlueZ的对比)
    dumpsys 用法
    ffmpeg开发指南
    Python七大原则,24种设计模式
    总结工厂模式---简单工厂、工厂方法、抽象工厂
    抽象工厂(Abstract Factory)
    工厂模式(Factory Method)
    逻辑回归(Logistic Regression) ----转载
    随机森林(Random Forest)--- 转载
    时间序列分析
  • 原文地址:https://www.cnblogs.com/zzqvq/p/10276936.html
Copyright © 2011-2022 走看看