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注入

posted @ 2011-04-22 17:12  风云  阅读(1626)  评论(3编辑  收藏  举报