如何构建一个轻量级级的DI(依赖注入)
概念:依赖注入与IOC模式类似工厂模式,是一种解决调用者和被调用者依赖耦合关系的模式;它解决了对象之间的依赖关系,使得对象只依赖IOC/DI容器,不再直接相互依赖,实现松耦合,然后在对象创建时,由IOC/DI容器将其依赖的对象注入其体内,故又称依赖注入依赖注射模式,最大程度实现松耦合;
那么什么是依赖?如下代码:
1 public class A{ 2 private B b; 3 public A(B b){ 4 this.b = b; 5 } 6 public void mymethod(){ 7 b.m(); 8 } 9 }
如下代码表示A依赖B,因为A的方法行为mymehtod有一部分要依赖B的方法m实现。
容器信息:
1 /// <summary> 2 /// 依赖注入中的配置项(注入容器) 3 /// </summary> 4 public class MapItem : { 5 6 private Boolean _singleton = true; 7 private Dictionary<String, String> _maps = new Dictionary<String, String>(); 8 9 /// <summary> 10 /// 容器创建对象的时候,是否以单例模式返回 11 /// </summary> 12 public Boolean Singleton { 13 get { return _singleton; } 14 set { _singleton = value; } 15 } 16 17 /// <summary> 18 /// 对象依赖注入关系的 map 19 /// </summary> 20 public Dictionary<String, String> Map { 21 get { return _maps; } 22 set { _maps = value; } 23 } 24 25 /// <summary> 26 /// 对象的 typeFullName 27 /// </summary> 28 public String Type { get; set; } 29 30 /// <summary> 31 32 /// 添加注入关系 33 34 /// </summary> 35 36 /// <param name="propertyName">属性名称</param> 37 38 /// <param name="item">注入容器</param> 39 internal void AddMap( String propertyName, MapItem item ) { 40 AddMap( propertyName, item.Name ); 41 } 42 43 /// <summary> 44 45 /// 注入 46 47 /// </summary> 48 49 /// <param name="propertyName">属性名称</param> 50 51 /// <param name="injectBy">对象名称</param> 52 internal void AddMap( String propertyName, String injectBy ) { 53 this.Map.Add( propertyName, injectBy ); 54 } 55 56 57 private Object _obj; 58 59 /// <summary> 60 61 /// 目标对象 62 63 /// </summary> 64 [NotSave] 65 internal Object TargetObject { 66 get { return _obj; } 67 set { _obj = value; } 68 } 69 70 private Type _type; 71 72 /// <summary> 73 74 /// 目标类型 75 76 /// </summary> 77 [NotSave] 78 internal Type TargetType { 79 get { 80 81 if (_type != null) return _type; 82 if (TargetObject != null) return TargetObject.GetType(); 83 return null; 84 } 85 set { _type = value; } 86 } 87 88 }
那么看如何使用这个容器,我们一般外部需要调用的方法为:
/// <summary> /// 创建一个经过Ioc处理的对象,结果不是单例。 /// 检测是否需要注入。 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static T Create<T>() { return (T)CreateObject(typeof(T), null); } /// <summary> /// 创建一个经过Ioc处理的对象,结果不是单例。 /// 检测是否需要注入。 /// </summary> /// <param name="targetType"></param> /// <param name="invokerName">如果是根据接口自动装配,</param> /// <returns></returns> private static Object CreateObject(Type targetType, Object invoker) { if (targetType == null) return null; if (targetType.IsInterface) { ///接口 return CreateByInterface(targetType, invoker); } //这里是用AOP实现对象的构建,可以参看上一篇博客 Object objTarget = AopContext.CreateObjectBySub(targetType); //进行IOC注入 Inject(objTarget); return objTarget; } /// <summary> /// 根据容器配置(IOC),将依赖关系注入到已创建的对象中 /// </summary> /// <param name="obj"></param> public static void Inject(Object obj) { if (obj == null) return; Type t = obj.GetType(); MapItem mapItem = getMapItemByType(t); if (mapItem == null) { mapItem = new MapItem(); mapItem.TargetType = t; mapItem.TargetObject = obj; } createInstanceAndInject(mapItem, obj); } /// <summary> /// 根据类型查找DI容器 /// </summary> /// <param name="t"></param> /// <returns></returns> private static MapItem getMapItemByType(Type t) { Dictionary<String, MapItem> resolvedMap = Instance.ResolvedMap;//当前对象的键值对容器 foreach (KeyValuePair<String, MapItem> entry in resolvedMap) { MapItem item = entry.Value; if (t.FullName.Equals(item.Type)) return item; } return null; } /// <summary> /// IOC注入:检查对象的属性,根据配置注入,如果没有配置,则自动装配 /// </summary> /// <param name="mapItem"></param> /// <returns></returns> private static Object createInstanceAndInject(MapItem mapItem, Object objTarget) { Type targetType = mapItem.TargetType; if (targetType.IsAbstract) { logger.Info("type is abstract=>" + targetType.FullName); return null; } if (objTarget == null) { objTarget = rft.GetInstance(targetType);//根据反射创建对象 } // 检查所有属性 PropertyInfo[] properties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo p in properties) { if (!p.CanRead) continue; if (!p.CanWrite) continue; // 不是接口的跳过 if (!p.PropertyType.IsInterface) continue; // 对接口进行注入检查 //------------------------------------------------- // 如果有注入配置 Object mapValue = getMapValue(mapItem.Map, p); if (mapValue != null) { p.SetValue(objTarget, mapValue, null); } // 如果没有注入 else { Object propertyValue = p.GetValue(objTarget, null); // 自动装配 if (propertyValue == null) { logger.Info("property=>" + targetType.Name + "." + p.Name); propertyValue = getAutoWiredValue(p.PropertyType); if (propertyValue != null) { p.SetValue(objTarget, propertyValue, null); } else { logger.Info("property is null=>" + p.Name); } } } } return objTarget; }
容器检查如果没有则自动装配
// IOC注入:检查对象的属性,根据配置注入,如果没有配置,则自动装配 private static Object createInstanceAndInject(MapItem mapItem) { return createInstanceAndInject(mapItem, null); } /// <summary> /// 检查映射关系中是否存在属性信息 /// </summary> /// <param name="maps"></param> /// <param name="p"></param> /// <returns></returns> private static Object getMapValue(Dictionary<String, String> maps, PropertyInfo p) { if (maps == null || maps.Count == 0) return null; foreach (KeyValuePair<String, String> entry in maps) { Object x = GetByName(entry.Value); if (x != null) return x; } return null; } /// <summary> /// 根据依赖注入的配置文件中的 name 获取对象。根据配置属性Singleton决定是否单例。 /// </summary> /// <param name="objectName"></param> /// <returns></returns> public static Object GetByName(String objectName) { if (Instance.ResolvedMap.ContainsKey(objectName) == false) return null; MapItem item = Instance.ResolvedMap[objectName]; if (item == null) return null; if (item.Singleton) return Instance.ObjectsByName[objectName]; else return createInstanceAndInject(item); }
根据接口自动绑定对象
// 根据接口,获取自动绑定的值 private static Object getAutoWiredValue(Type interfaceType) { List<Type> typeList = GetTypeListByInterface(interfaceType); if (typeList.Count == 0) { return null; // 返回null } else if (typeList.Count == 1) { return Create(typeList[0], interfaceType); } else { StringBuilder msg = new StringBuilder(); foreach (Type t in typeList) { msg.Append(t.FullName + ","); } throw new Exception(string.Format("有多个接口实现,接口={0},实现={1} 没有明确指定,无法自动注入。", interfaceType.FullName, msg)); } } // 根据接口获取实例 public static List<Type> GetTypeListByInterface(Type interfaceType) { List<Type> typeList = new List<Type>(); foreach (KeyValuePair<String, Type> kv in Instance.TypeList) { if (rft.IsInterface(kv.Value, interfaceType)) { typeList.Add(kv.Value); } } return typeList; }