zoukankan      html  css  js  c++  java
  • DI 容器Mini容器工作机制剖析(下篇)

      上篇介绍了DI容器最基本功能,组件注册和组件创建和组件获取。这里将陆续把依赖注入进行详细介绍。

         1.  看看组件工厂接口-IActivator的代码:

    /// <summary>
    /// 组件工厂
    /// </summary>
    public interface IActivator
    {
    /// <summary>
    /// 创建组件
    /// </summary>
    /// <param name="ctx">创建上下文</param>
    /// <returns>返回所创建的组件</returns>
    object Create(IPreCreationContext ctx);
    }

       2. AbstractActivator 抽象组件工厂定义了创建组件的一系列模板步骤,具体的子类只要实现各自的具体步骤即可,下面是抽象组件工厂的源代码:

    /// <summary>
        /// 抽象组件工厂
        /// </summary>
        [Serializable]
        public abstract class AbstractActivator : BooleanDisposable, IActivator
        {
            private readonly object SyncRoot = new object();
            private bool hasLock;
    
            /// <summary>
            /// 创建组件
            /// </summary>
            /// <param name="context">创建上下文</param>
            /// <returns>返回所创建的组件</returns>
            public virtual object Create(IPreCreationContext context)
            {
    
                //1. 记录并跟踪组件创建的对象图
                Tracker.Track(context);
    
                //2. 检查是否循环依赖创建组件,如果是Throw LoopDependencyException
                if (hasLock)
                    throw ExceptionManager.HandleAndWrapper<LoopDependencyException>(Tracker.CallStack);
    
                object instance = null;
    
                lock (SyncRoot)
                {
                    hasLock = true;
    
                    //3. 得到组件监听管理器
                    var componentListner = context.Kernel.ListenerManager as IComponentListener;
    
                    //4. 在组件创建前进行监听
                    if (componentListner != null)
                        componentListner.OnPreCreation(context);
                   
                    //5. 具体的 Create instance
                    instance = InternalCreate(context);
    
                    if (componentListner != null)
                    {
                        //6. 在组件创建后进行监听(这里就是依赖注入的扩张点)
                        var postCreateContext = new PostCreationContext(context.Kernel, context.Component, instance);
                        componentListner.OnPostCreation(postCreateContext);
    
                        //7. 在组件创建后对组件初始化进行监听
                        componentListner.OnInitialization(postCreateContext);
                        //8. 在组件初始化后进行监听
                        componentListner.OnPostInitialization(postCreateContext);
                    }
    
                    Tracker.Clear();
    
                    hasLock = false;
                }
    
                return instance;
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            protected virtual object InternalCreate(IPreCreationContext context) { throw new NotImplementedException(); }
        }
    

    通过代码可以看出组件工厂里面并没有提供任何依赖注入的扩展,但是有一系列组件监听器的监听方法:

    • OnPreCreation
    • OnPostCreation
    • OnInitialization
    • OnPostInitialization

    通过这些监听方法可以非常方便的对组件内部的字段,属性进行初始化(也就是依赖注入)

      3. 完整的组件监听器接口定义:

     /// <summary>
        /// 组件监听阶段枚举
        /// </summary>
        [Flags]
        public enum ComponentListenStage
        {
            /// <summary>
            /// 空
            /// </summary>
            None = 1,
    
            /// <summary>
            /// 组件元数据注册后阶段
            /// </summary>
            MetadataRegistered = None * 2,
    
            /// <summary>
            /// 组件创建前阶段
            /// </summary>
            PreCreation = MetadataRegistered * 2,
    
            /// <summary>
            /// 组件创建后阶段
            /// </summary>
            PostCreation = PreCreation * 2,
    
            /// <summary>
            /// 初始化阶段
            /// </summary>
            Initialization = PostCreation * 2,
    
            /// <summary>
            /// 初始化后阶段
            /// </summary>
            PostInitialization = Initialization * 2,
    
            /// <summary>
            /// 组件释放前阶段
            /// </summary>
            PreDestroy = PostInitialization * 2,
    
            /// <summary>
            /// 组件释放后阶段
            /// </summary>
            PostDestroy = PreDestroy * 2,
        }
    
    
        /// <summary>
        /// 组件监听器接口,在组件元数据注册,组件创建前后,组件初始化前后以及组件释放前后进行监听
        /// </summary>
        [Contract]
        public interface IComponentListener:IListener<ComponentListenStage>
        {
            /// <summary>
            /// 初始化监听器
            /// </summary>
            /// <param name="kernel"></param>
            void Init(IKernel kernel);
    
            /// <summary>
            /// 得到内核容器对象
            /// </summary>
            IKernel Kernel { get;  }
    
            /// <summary>
            /// 在组件元数据注册后进行监听,例如Aop监听器
            /// </summary>
            /// <param name="info"></param>
            void OnMetadataRegistered(IComponentInfo info);
    
            /// <summary>
            /// 在组件创建前进行监听
            /// </summary>
            /// <param name="ctx"></param>
            void OnPreCreation(IPreCreationContext ctx);
    
            /// <summary>
            /// 在组件创建后进行监听
            /// </summary>
            /// <param name="ctx"></param>
            void OnPostCreation(IPostCreationContext ctx);
    
            /// <summary>
            /// 在组件创建后对组件初始化进行监听
            /// </summary>
            /// <param name="ctx"></param>
            void OnInitialization(IPostCreationContext ctx);
    
            /// <summary>
            /// 在组件初始化后进行监听
            /// </summary>
            /// <param name="ctx"></param>
            void OnPostInitialization(IPostCreationContext ctx);
    
            /// <summary>
            /// 在组件释放前进行监听
            /// </summary>
            /// <param name="info"></param>
            /// <param name="instance"></param>
            void OnPreDestroy(IComponentInfo info, object instance);
    
            /// <summary>
            /// 在组件释放后进行监听
            /// </summary>
            /// <param name="info"></param>
            void OnPostDestroy(IComponentInfo info);
        }
    

      4. Mini容器构造函数里面默认注册的组件监听器:

            public Kernel(
                IComponentListenerManager listnerManager,
                ILifestyleManagerFactory lifestyleManagerRegistry,
                IActivatorFactory activatorFactory,
                IClassLoader classLoader)
            {
                ListenerManager = listnerManager;
                LifestyleManagerRegistry = lifestyleManagerRegistry;
                ActivatorRegistry = activatorFactory;
    
                IdStores = new ConcurrentMap<string, ComponentPair>(StringComparer.OrdinalIgnoreCase);
                TypeStores = new ConcurrentMap<Type, List<ComponentPair>>();
    
                Listner = ListenerManager as IComponentListener;
    
                RegisterInstance("ServiceLocator", typeof(IServiceLocator), this);
                RegisterInstance("ServiceRegistry", typeof(IServiceRegistry), this);
                
    
                if (classLoader != null)
                    RegisterInstance(AppDomain.CurrentDomain.Id.ToString() + ":" + classLoader.GetType(), typeof(IClassLoader), classLoader);
    
                if (ListenerManager != null)
                    ListenerManager.Init(this);
    
                RegisterListners();
            }
    
            //注册默认监听器
            private void RegisterListners()
            {
                ListenerManager.Register(new AopListener());//Aop监听器
                ListenerManager.Register(new DisposalListener());//Dispose监听器
                ListenerManager.Register(new InitializationListener());//初始化监听器
                ListenerManager.Register(new SupportInitializeListener());//Support初始化监听器
                ListenerManager.Register(new StartableListener());//启动停止监听器
                ListenerManager.Register(new SubscribeListener());//消息总线的订阅监听器
                ListenerManager.Register(new InjectionListener());//注入监听器
                ListenerManager.Register(new InjectionManyListener());//批量注入监听器
                ListenerManager.Register(new ComponentMemberRegisterListner());//组件成员导出与注入监听器
                ListenerManager.Register(new AppSettingInjectionListener());//AppSetting注入监听器
            }
    
    
            /// <summary>
            /// 父容器
            /// </summary>
            public IKernel Parent { get; set; }
    
            /// <summary>
            /// 组件监听管理器
            /// </summary>
            public IComponentListenerManager ListenerManager { get; private set; }
           
    

      5. Mini容器提供了很多监听器,下面看看注入监听器的代码:

    using System.Linq;
    using NLite.Mini.Context;
    using NLite.Reflection;
    using NLite.Collections;
    using System.Reflection;
    using NLite.Mini.Internal;
    using NLite.Mini.Listener.Internal;
    using NLite.Reflection.Internal;
    
    namespace NLite.Mini.Listener
    {
        /// <summary>
        /// 注入监听器
        /// </summary>
        public sealed class InjectionListener:ComponentListenerAdapter
        {
            private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
            private const BindingFlags FieldFlags = BindingFlags.SetField | Flags;
            private const BindingFlags PropertyFlags = BindingFlags.SetProperty | Flags;
    
            /// <summary>
            /// 
            /// </summary>
            public InjectionListener():base(ComponentListenStage.PostCreation)
            {
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="ctx"></param>
            public override void OnPostCreation(NLite.Mini.Context.IPostCreationContext ctx)
            {
                if (ctx.Instance == null)
                    return;
    
                const string Key = "InjectionMany";
                Lazy<InjectionInfo[]> lazy = null;
                if (ctx.Component.ExtendedProperties.Contains(Key))
                    lazy = ctx.Component.ExtendedProperties[Key] as Lazy<InjectionInfo[]>;
    
                if (lazy == null)//基于Lazy的方式创建组件的注入元数据
                {
                    lazy = new Lazy<InjectionInfo[]>(() =>
                    {
                        var instanceType = ctx.Instance.GetType();
                        return (from f in instanceType.GetFields(FieldFlags)
                                let att = f.GetAttribute<InjectAttribute>(true)//字段上有InjectAttribute标签
                                let ignoreAtt = f.GetAttribute<IgnoreInjectAttribute>(true)
                                let id = att != null ? att.Id : string.Empty
                                where ignoreAtt == null
                                where att != null
                                where !f.HasAttribute<InjectManyAttribute>(false)
                                select new InjectionInfo//字段注入元数据
                                {
                                    Id = id
                                    ,
                                    Source = InjectionSource.Container
                                    ,
                                    Setter = f.ToMemberSetter()//通过Emit的方式进行注入
                                    ,
                                    MemberType = f.FieldType
                                }
    
                           )
                           .Union(
                           from p in instanceType.GetProperties(PropertyFlags)
                           let ps = p.GetIndexParameters()
                           let att = p.GetAttribute<InjectAttribute>(false)
                           let ignoreAtt = p.GetAttribute<IgnoreInjectAttribute>(false)
                           let id = att != null ? att.Id : string.Empty
                           where ignoreAtt == null || ps == null || ps.Length == 0
                           where att != null
                           where !p.HasAttribute<InjectManyAttribute>(false)
                           select new InjectionInfo//属性注入元数据
                           {
                               Id = id
                               ,
                               Setter = p.ToMemberSetter()//通过Emit的方式进行注入
    
                               ,
                               MemberType = p.PropertyType
                               ,
                               Source = InjectionSource.Container
                           })
                           .Union(
                           from m in instanceType.GetMethods(Flags)
                           let ps = m.GetParameters()
                           let att = m.GetAttribute<InjectAttribute>(false)
                           let ignoreAtt = m.GetAttribute<IgnoreInjectAttribute>(false)
                           where ignoreAtt == null
                                 && m.ReturnType == Types.Void
                                 && att != null
                                 && ps.TrueForAll(p => !p.HasAttribute<InjectManyAttribute>(false))
                           select new InjectionInfo//方法注入元数据
                           {
                               Id = att.Id
                               ,
                               Method = DynamicMethodFactory.GetProc(m)
                               ,
                               Parameters = ps
                               ,
                               Source = InjectionSource.Container
                           }
                           ).ToArray();
                    });
    
                    ctx.Component.ExtendedProperties[Key] = lazy;
                }
    
                if (lazy.Value.Length == 0)//没有注入元数据则返回
                    return;
    
                foreach (var item in lazy.Value)
                {
                    if (item.MemberType != null)//是字段或属性注入吗
                        InjectMember(ctx, item);
                    else
                        InjectMemberByMethod(ctx, item);//方法注入
                }
            }
    
            //执行方法注入
            private static void InjectMemberByMethod(IPostCreationContext ctx, IInjectionInfo item)
            {
                item.Method(ctx.Instance, ReflectionHelper.GetParameters(ctx.Kernel, item.Parameters));
            }
    
            //执行字段注或属性注入
            private static void InjectMember(IPostCreationContext ctx, IInjectionInfo item)
            {
                if (!MemberMatcher.Match(item.MemberType, ctx.Kernel))
                    return;
                item.Setter(ctx.Instance, InjectService.Get(item.Id, item.MemberType, ctx.Kernel, false));
            }
        }
    }
    

      从注入监听器的代码中可以看出,当组件创建后,注入监听器将扫描组件的所有字段,属性和方法,找出所有可以被注入的成员,然后对这些成员进行注入。

      具体注入的过程就是,通过注入的元数据找到依赖的组件类型或组件Id,然后根据组件类型或Id从DI容器中找出对应的依赖组件,然后把该依赖的组件通过字段,属性或方法调用的方式进行初始化,这样就完成了注入。

      上篇文章全是文字没有代码,这篇基本上全是用代码堆起来的,文字很少,不过代码中有很多注释,通过代码注释基本上可以了解整个被注入的过程。通过这两篇文章已经把Mini容器的整个精髓和骨架勾勒出来,注册组件->创建组件元数据(Id,组件类型,组件契约,生命周期管理器,组件工厂),获取组件->组件生命周期管理器->组件工厂->组件监听器(依赖注入等),通过上篇的脑图可以更详细的了解Mini容器的内部结构, 望能够给那些对DI容器不太了解或对DI容器工作机制不太了解的朋友给些帮助,这样就够了!  

        为了加深大家对Mini容器DI容器更进一步了解,下面提供3个有关字段注入,属性注入,方法注入等的链接

    Mini 容器学习笔记7——构造函数注入

    Mini 容器学习笔记8——字段注入

    Mini 容器学习笔记9——属性注入

    Mini 容器学习笔记10——方法注入

    Mini 容器学习笔记11——Lazy注入

  • 相关阅读:
    简单的html5 File base64 图片上传
    PHP CURL POST
    PHP常用代码段:
    使用Sqlserver事务发布实现数据同步(转)
    几个SQL小知识(转)
    Sql语句摘要
    C#创建服务及使用程序自动安装服务,.NET创建一个即是可执行程序又是Windows服务的exe(转)
    说说C#的async和await(转)
    c#并发编程经典实例文摘
    [在职软件工程]数据挖掘-概念与技术
  • 原文地址:https://www.cnblogs.com/netcasewqs/p/2024967.html
Copyright © 2011-2022 走看看