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个有关字段注入,属性注入,方法注入等的链接