上篇介绍了DI容器最基本功能,组件注册和组件创建和组件获取。这里将陆续把依赖注入进行详细介绍。
1. 看看组件工厂接口-IActivator的代码:
/// 组件工厂
/// </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个有关字段注入,属性注入,方法注入等的链接