如何构建一个轻量级级的DI(依赖注入)
概念:依赖注入与IOC模式类似工厂模式,是一种解决调用者和被调用者依赖耦合关系的模式;它解决了对象之间的依赖关系,使得对象只依赖IOC/DI容器,不再直接相互依赖,实现松耦合,然后在对象创建时,由IOC/DI容器将其依赖的对象注入其体内,故又称依赖注入依赖注射模式,最大程度实现松耦合;
那么什么是依赖?如下代码:
public class A{
private B b;
public A(B b){
this.b = b;
}
public void mymethod(){
b.m();
}
}
如下代码表示A依赖B,因为A的方法行为mymehtod有一部分要依赖B的方法m实现。
容器信息:
/// <summary>
/// 依赖注入中的配置项(注入容器)
/// </summary>
public class MapItem : { private Boolean _singleton = true;
private Dictionary<String, String> _maps = new Dictionary<String, String>(); /// <summary>
/// 容器创建对象的时候,是否以单例模式返回
/// </summary>
public Boolean Singleton {
get { return _singleton; }
set { _singleton = value; }
} /// <summary>
/// 对象依赖注入关系的 map
/// </summary>
public Dictionary<String, String> Map {
get { return _maps; }
set { _maps = value; }
} /// <summary>
/// 对象的 typeFullName
/// </summary>
public String Type { get; set; } /// <summary> /// 添加注入关系 /// </summary> /// <param name="propertyName">属性名称</param> /// <param name="item">注入容器</param>
internal void AddMap( String propertyName, MapItem item ) {
AddMap( propertyName, item.Name );
} /// <summary> /// 注入 /// </summary> /// <param name="propertyName">属性名称</param> /// <param name="injectBy">对象名称</param>
internal void AddMap( String propertyName, String injectBy ) {
this.Map.Add( propertyName, injectBy );
} private Object _obj; /// <summary> /// 目标对象 /// </summary>
[NotSave]
internal Object TargetObject {
get { return _obj; }
set { _obj = value; }
} private Type _type; /// <summary> /// 目标类型 /// </summary>
[NotSave]
internal Type TargetType {
get { if (_type != null) return _type;
if (TargetObject != null) return TargetObject.GetType();
return null;
}
set { _type = value; }
} }
那么看如何使用这个容器,我们一般外部需要调用的方法为:
/// <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 == ) 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 == )
{
return null; // 返回null
}
else if (typeList.Count == )
{
return Create(typeList[], 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;
}
如何构建一个轻量级级的DI(依赖注入)的更多相关文章
- Spring详解(三)------DI依赖注入
上一篇博客我们主要讲解了IOC控制反转,也就是说IOC 让程序员不在关注怎么去创建对象,而是关注与对象创建之后的操作,把对象的创建.初始化.销毁等工作交给spring容器来做.那么创建对象的时候,有可 ...
- 三大框架 之 Spring(IOC控制反转、DI依赖注入)
目录 常用词汇 left join与left outer join的区别 Struts2的标签库导入 Spring Spring概述 什么是Spring spring特点 下载 IOC 什么IOC 传 ...
- 手写Spring DI依赖注入,嘿,你的益达!
目录 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBeanFa ...
- .net 温故知新:【7】IOC控制反转,DI依赖注入
IOC控制反转 大部分应用程序都是这样编写的:编译时依赖关系顺着运行时执行的方向流动,从而生成一个直接依赖项关系图. 也就是说,如果类 A 调用类 B 的方法,类 B 调用 C 类的方法,则在编译时, ...
- 初识Spring框架实现IOC和DI(依赖注入)
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的, IoC是 ...
- 谈谈php里的IOC控制反转,DI依赖注入
理论 发现问题 在深入细节之前,需要确保我们理解"IOC控制反转"和"DI依赖注入"是什么,能够解决什么问题,这些在维基百科中有非常清晰的说明. 控制反转(In ...
- DI依赖注入/IOC控制反转
DI依赖注入# 啥都不说,直接上代码 <?php class UserController { private $user; function __construct(UserModel $us ...
- IoC控制反转与DI依赖注入
IoC控制反转与DI依赖注入 IoC: Inversion of Control IoC是一种模式.目的是达到程序的复用.下面的两篇论文是对IoC的权威解释: InversionOfControl h ...
- Spring:(二)DI依赖注入方式
DI 依赖注入 DI(Dependency Injection)依赖注入,说简单一点就将类里面的属性在创建类的过程中给属性赋值,即将对象依赖属性(简单值,集合,对象)通过配置设值给该对象. 属性注入的 ...
随机推荐
- P3709 大爷的字符串题(50分)
题目背景 在那遥远的西南有一所学校 /*被和谐部分*/ 然后去参加该省省选虐场 然后某蒟蒻不会做,所以也出了一个字符串题: 题目描述 给你一个字符串a,每次询问一段区间的贡献 贡献定义: 每次从这个区 ...
- 【Linux】七种运行级别
运行级别:即系统的运行模式. 级别类型: 0:关机状态. 1:单用户模式. 2:字符界面的多用户模式(不支持网络). 3:字符界面的多用户模式(运行最完整的模式). 4:未分配使用,系统保留. 5:图 ...
- C# 7.0新加特性
以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉 ...
- dubbo之启动时检查
启动时检查 Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认 check="true".所以可以通过 ...
- JavaOO知识点小结一
Java语言的特点是什么?简单 面向对象 跨平台 多线程 健壮性安全性 垃圾回收机制如何编译和执行java文件?产生帮助文档用什么命令?编译: javac 文件名执行: java 类名产生帮助文档 j ...
- [Intermediate Algorithm] - Finders Keepers
题目 写一个 function,它浏览数组(第一个参数)并返回数组中第一个通过某种方法(第二个参数)验证的元素. 提示 Array.filter() 测试用例 find([1, 3, 5, 8, 9, ...
- MVC 返回404,返回图片,流到数组,apk信息
return HttpNotFound(); byte[] buffer0 = QRCode(); return File(buffer0, @"image/jpeg"); // ...
- PHP实现文字写入图片功能
/** * PHP实现文字写入图片 */class wordsOnImg { public $config = null; /** * @param $config 传入参数 * @param $co ...
- Linux基础:seq命令总结
本文只总结一些常用的用法,更详细的说明见man seq和 seq --help. seq命令 seq命令用于输出数字序列. 语法格式 Usage: seq [OPTION]... LAST or: s ...
- C#第六节课
for循环 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System ...