zoukankan      html  css  js  c++  java
  • 如何构建一个轻量级级的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;
            }
  • 相关阅读:
    has a / is a 的区别
    Linux头文件作用
    转一篇Decorator模式的讲解文章
    歌手推荐kate st. john
    拷贝构造函数和赋值构造函数声明为私有的作用
    重新认识C++中new的用法
    系统程序员成长计划容器与算法(二)(下)
    深入C++的new
    歌手推荐Cara Dillon
    浅析一道C++设计面试题
  • 原文地址:https://www.cnblogs.com/hui088/p/4580954.html
Copyright © 2011-2022 走看看