如何构建一个轻量级级的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)依赖注入,说简单一点就将类里面的属性在创建类的过程中给属性赋值,即将对象依赖属性(简单值,集合,对象)通过配置设值给该对象. 属性注入的 ...
随机推荐
- angular的directive指令的link方法
比如 指令标签 <mylink myLoad="try()"></mylink> link:function(scope,element,attr){ el ...
- wap网测一道题目
1. 给定一个字符串s, 1 <= len(s) <= 3000, 定义odd palindrome string为长度为奇数的回文串, 求s中该奇回文串的个数. 比如axbcba , 结 ...
- F - Micro-World(简单模拟)
Problem description You have a Petri dish with bacteria and you are preparing to dive into the harsh ...
- Jenkins构建项目,JAVA_HOME is not defined correctly
好久都没有更新了,由于职位调整,开始捣鼓持续集成的东西了.jenkins的基本安装配置网上有很多教程,不用多讲了,就记录下我在使用过程中遇到的一些问题.话说这个jenkins环境以及安装好了有一段时间 ...
- Jsp页面报错状态码含义
原来,全部在HttpServletResponse接口的字段里 状态码 (),表示一个请求已经被接受处理,但还没有完成. 状态码 (),表明HTTP服务器从一个服务器收到了一个无效的响应,当其作为一 ...
- P1401 城市(30分,正解网络流)
题目描述 N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能 ...
- bootstrap表格样式
一:表格基本格式 <table> <tr> <th>标题一</th> <th>标题二</th> </tr> < ...
- 使用 gradle 在编译时动态设置 Android resValue / BuildConfig / Manifes中<meta-data>变量的值
转载请说明来源: http://www.cnblogs.com/lizhilin2016/p/7390079.html 最近lz 在开始做一个新的Demo, 在项目中集成了bugly用于收集项目中的崩 ...
- C# 7.0新加特性
以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio “15” Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉 ...
- 【sqli-labs】 less1 GET - Error based - Single quotes - String(GET型基于错误的单引号字符型注入)
GET方式提交id参数 添加单引号,出现报错,爆出数据库名称和部分SQL语句 http://localhost/sqli/Less-1/?id=1' 使用order by猜测字段数,用#注释掉后面li ...