概念:依賴注入與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; }