一个效率是Unity 5-7倍的IOC容器分享。
测试效果看上传的图片源码地址
https://github.com/mt830813/IOCFactory
示例地址
https://github.com/mt830813/IOCFactory/tree/master/IOCFactoryUnitTest目前已经用在公司内部的一个项目中。
支持json与unitySetting.xml两种文件格式的注册由于是个人处于兴趣写的。所以有不足之处欢迎批评与建议。
对于性能方面的建议尤其欢迎。
ioc开源源码
测试效果看上传的图片源码地址
https://github.com/mt830813/IOCFactory
示例地址
https://github.com/mt830813/IOCFactory/tree/master/IOCFactoryUnitTest目前已经用在公司内部的一个项目中。
支持json与unitySetting.xml两种文件格式的注册由于是个人处于兴趣写的。所以有不足之处欢迎批评与建议。
对于性能方面的建议尤其欢迎。
ioc开源源码
对于任何底层级别的效率的进步都是有意义的。
特别是大型项目中,基本上所有的对象都是由IOC容器实现。
那一个比传统的IOC容器快N倍的实现怎么会意义不大呢?
这个是Bean 不是单例
@Bean(singleton=false)
public class UserController { @Inject
private UserService userService; public String list() {
return userService.list();
}}
这个是测试类
public class Test { public static void main(String[] args) {
ApplicationContext ctx = new ApplicationContext();
UserController controller = null;
long l1 = System.currentTimeMillis();
for(int i = 1000 * 1000; i > 0; i--) {
controller = ctx.getBean(UserController.class);
}
long l2 = System.currentTimeMillis();
System.out.format("time: %d ms\n", l2 - l1); ctx.close();
}}
结果是:time: 860 ms
目前我的容器已经可以做到读取json or unity格式的xml来进行刚实现的按照untiy的.config 中的section格式来进行注册。
貌似不行
那我就在后面跟吧。。
2013.10.24 17:00更新
更新说明:
1、更正之前的unity的mapping xml格式以及读取方式
2、增加读取写在.config文件中的unity格式的section来进行注册的方式
3、增加了.config文件的section handler.具体例子表现为:
setting.xml<?xml version="1.0" encoding="utf-8" ?>
<unity>
<typeAliases>
<typeAlias alias="Interface" type="IOCFactoryUnitTest.Animal,IOCFactoryUnitTest"/>
<typeAlias alias="Object" type="IOCFactoryUnitTest.Dog,IOCFactoryUnitTest"/>
</typeAliases>
<containers>
<container name="containerOne">
<types>
<type type="Interface" mapTo="Object">
<lifetime type="singleton"/>
</type>
</types>
</container>
</containers>
</unity>.config<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="IOCFactory.Util.IOCFactoryUnitySectionHandler,IOCFactory"/>
</configSections>
<unity configSource="setting.xml" />
</configuration>
注册调用 factory.RegistFromSection("unity");
详情可以看我的开源站点的 IOCFactory.Test里面的示例.
他的核心算法和我的核心算法有本质的区别。
这才是速度有区别的根本原因。
你错了。
他的核心算法和我的核心算法有本质的区别。
这才是速度有区别的根本原因。
有多大区别,不都是一个类型注册表字典,然后通过反射什么的查找构造方法啊用lambda表达式之类的实例化类型
他的核心算法和我的核心算法有本质的区别。
这才是速度有区别的根本原因。
你错了。
他的核心算法和我的核心算法有本质的区别。
这才是速度有区别的根本原因。
有多大区别,不都是一个类型注册表字典,然后通过反射什么的查找构造方法啊用lambda表达式之类的实例化类型
你已经充分帮我说明了我和Unity的核心算法的区别。
这个概念其实很多人应该都已经知道了。
大概来说呢。是这样的。
反射的原理,就是通过Type来操作类。非常简单方便。
但是呢会出现一个问题。就是每次调用都会重新去寻找我们所需要的调用。
这样在反复调用的时候就会比传统的直接调用慢相当多。
而快速反射的原理呢,是将我们期望通过反射实现的动作缓存起来。
以提高反复调用相同动作时的效率。
但是由于有些动作并没有直接的对象来进行缓存,所以就采用lamda或则IL的方式来将委托得到。
这就是快速反射了。
是我的博客。希望大家与我在上面交流技术方面的问题。
我也会时常将一些我的代码或则心得分享在上面。
重新发一遍。hoho
这个概念其实很多人应该都已经知道了。
大概来说呢。是这样的。
反射的原理,就是通过Type来操作类。非常简单方便。
但是呢会出现一个问题。就是每次调用都会重新去寻找我们所需要的调用。
这样在反复调用的时候就会比传统的直接调用慢相当多。
而快速反射的原理呢,是将我们期望通过反射实现的动作缓存起来。
以提高反复调用相同动作时的效率。
但是由于有些动作并没有直接的对象来进行缓存,所以就采用lamda或则IL的方式来将委托得到。
这就是快速反射了。
如果只是想增加一点“缓存”伎俩,那么我们可以使用.net framework中早10年就有的 TypeDescriptor 类。因为这个类只是第一次反射对象类,以后就直接返回缓存结果了。如果想要一点更高级功能,那么我们可以使用.net framework中内置的标准化的 MEF。最后,无论如何,弄一堆xml文件的做法都不是.net的风格。
另外。确实我这个不是什么新玩意。但是市面上也确实没有一个比较快速的IOC出现。难道不就是问题么?
何况,我也并不觉得我写的这个东西有什么了不起。只是希望在IOC容器层面和大家聊聊性能问题。以及思想碰撞一下。仅此而已。
从小事看大。。不要好高骛远。
什么都谈设计谈设计,确不接地气。只知道用现成的架构,而不知道架构的原理或则说,并没有真正理解结构的原理。
另外。弄出一堆xml的做法怎么就不是.net的风格了?
.config文件不是xml?
wcf的一堆注册不是xml?
wpf也是标签化结构来写的。不也是类xml?
unity的注册不是xml?不是为了支持unity的注册格式,我干嘛用xml?
貌似unity是microsoft的标准企业库吧?
还有什么sharepoint。csp平台不都是xml结构化?
另外。确实我这个不是什么新玩意。但是市面上也确实没有一个比较快速的IOC出现。难道不就是问题么?
何况,我也并不觉得我写的这个东西有什么了不起。只是希望在IOC容器层面和大家聊聊性能问题。以及思想碰撞一下。仅此而已。
从小事看大。。不要好高骛远。
什么都谈设计谈设计,确不接地气。只知道用现成的架构,而不知道架构的原理或则说,并没有真正理解结构的原理。
另外。弄出一堆xml的做法怎么就不是.net的风格了?
.config文件不是xml?
wcf的一堆注册不是xml?
wpf也是标签化结构来写的。不也是类xml?
unity的注册不是xml?不是为了支持unity的注册格式,我干嘛用xml?
貌似unity是microsoft的标准企业库吧?
还有什么sharepoint。csp平台不都是xml结构化?你别理他,他就那样我还等着你说你的架构呢比如说分成三大模块 配置 缓存 调用配置使用了工厂模式 或者 组合模式等 能支持配置或者程序创建等调用使用了 快速反射技术 等,最好有架构图说明一下当然以上说的没有也没有什么关系,我感兴趣的是这些
初级的使用方式是使用Regist,和get.
这样就使得代码只和IOC容器以及接口耦合。
再进一步的解耦就是将代码只与要调用的接口耦合,也就是DI了。
Ps.
一个类型要注册两个对象的话,可以使用Key来进行区分。
Regist<T,Q>(Name,InstType)
另外我这里是使用如果Name为空,或则Name没有
我会去找DefaultName的注册。如果还没有将会抛出异常。
手边暂时没有合适的写Uml的工具。就先说说吧。。
明天上班了再补架构图。配置使用了2种格式。
Json和Unity.
支持的对象模式为。装饰者,单例,普通以及依赖注入。
领域模型的话分为以下几个。
工厂,辅助工厂,实例创建者和注册序列化工具。典型的用例为
注册:
调用工厂的普通注册或则文件注册。
如果为文件注册
将会找辅助工厂得到注册序列化工具
并将文件内容序列化为 注册对象。
然后工厂对将要的注册进行验证
通过验证后 注册成功。实例化对象为:
调用工厂的获取方法。
工厂根据传递的参数进行验证是否已经注册。
如果已经注册,将根据注册的类型不同,寻找辅助工厂得到 实例创建者。
然后返回实例创建者的创建结果。
并且所有的实例创建者最终都会依赖于普通实例创建者(由注册在辅助工厂里面的普通实例创建者决定)。
所以普通实例创建者的执行效率将会最终影响全局的实例化效率。
所以你的这个调用只要带构造参数的话性能肯定不行。
首先,我早已支持一接口调用的默认实现类。
其次,你看到的传统普通创建者是已经被Lambda普通创建者替代了的。
再次,我的所有的Get都支持params object[] 这个参数就是说明了我支持带参构造函数。
如果不支持带参构造函数,我怎么注入呢?
首先,我早已支持一接口调用的默认实现类。
其次,你看到的传统普通创建者是已经被Lambda普通创建者替代了的。
再次,我的所有的Get都支持params object[] 这个参数就是说明了我支持带参构造函数。
如果不支持带参构造函数,我怎么注入呢?
这个也是我当初性能优化提升最大的一个地方。
也是这里,造成了我的性能比Unity好。
//使用 老赵的 代码计时 IOrders Orders = null; CodeTimer.Time("IOCFactory 无构造参数", iteration, () =>
{
Orders = factory.Get<IOrders>("order");
});
//Orders.OrdersID 应该等于0,没有问题 CodeTimer.Time("IOCFactory 1个造参数", iteration, () =>
{
Orders = factory.Get<IOrders>("order", 1);
});
/* 同一实现对象的不同的构造 上下文 context.HashCode 是相同的,所有调用了首次生成的委托。
* Orders.OrdersID 应该等于1,但等于 = 0,即只调用首次生成对象的委托,虽然生成新的实例,但即是调用首次的创建对象的委托
* 这种在实际应用中要出问题的
*/
CodeTimer.Time("IOCFactory 2个造参数", iteration, () =>
{
Orders = factory.Get<IOrders>("order", 2, "张三");
}); //Orders.OrdersID 应该等于2,只可惜还是0 CodeTimer.Time("IOCFactory 3个造参数", iteration, () =>
{
Orders = factory.Get<IOrders>("order", 3, "张三", 9.0);
}); //Orders.OrdersID 应该等于3,但等于 = 0
另外:NormalInstCreator 这个类的可更新一下
将 Dictionary 改成 ConcurrentDictionary private static Func<int, ObjectActivator> BuilderObjectActivator(RegistObjectContext context, params object[] param)
{
return (HashCode) =>
{
var types = new Type[param.Length];
for (int i = 0; i < param.Length; i++)
{
types[i] = param[i].GetType();
}
var constructor = context.ObjType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, types, null);
return NormalInstCreator2.GetActivator(context.ObjType, constructor);
};
}
public object CreateInst(RegistObjectContext context, params object[] param)
{
// var fun = BuilderObjectActivator(context, param);
// fun(context.HashCode);
ObjectActivator objectCreater = dicCache.GetOrAdd(context.HashCode, BuilderObjectActivator(context, param));
return objectCreater(param);
}
但是目前我有几个疑问。
首先。经过我的测试,你说的第一个问题并不存在,所以我不知道是否是你注册的时候的问题。请帖上你的对象注册代码。
第二。为什么要用ConCurrentDictionary?请详细说明一下。如果能有实际的证例将会更好。
查了一下资料,原来ConCurrentDictionary是号称线程安全的Dictionary.
但是其实仔细研究一下就会发现,其实也并不怎么线程安全。
http://www.cnblogs.com/PurpleTide/archive/2011/11/21/2256577.html
上面的链接也许可以帮助你对它有更多的了解。
并欢迎使用我的Ioc容器。
正在策划下一个开源的东西,想法很多,还没选择好。
而楼主采用的是 读取不存在产生异常时,并捕捉异常时才加锁创建,其实这还不如直接在外加锁用 TryGetValue 来得快如:lock (Users)
{
string user;
if (!Users.TryGetValue(1, out user))
{
Users.Add(1, "张三");
}
}
因捕捉异常,产生的跟踪所花的时间更长,当然什么都需要测式出来证明,你创建多个线程试一下。
使用哪个字典都不是你这个IoC性能的最大问题,Ioc最大的还是创建对象,特别是不确定的构造参数,这种是比较麻烦的,楼主的这个各种构造参数都只会调用这个(类型 + 别名)的首个编译委托.创建一个简单的具有三种构造参数的对象(接口就不用写了)
public class Orders : IOrders
{
public Orders()
{ }
public Orders(int ordersID)
{
this.OrdersID = ordersID;
}
public Orders(int ordersID, string clientele)
{
this.OrdersID = ordersID;
this.Clientele = clientele;
}
public Orders(int ordersID, string clientele, double value)
{
this.OrdersID = ordersID;
this.Clientele = clientele;
this.Value = value;
}
public virtual int OrdersID { get; set; }
public double Value { get; set; }
public virtual string Clientele { get; set; }
}
注册:Factory factory = Factory.GetInst();
factory.Regist<IOrders, Orders>("a", IOCFactoryModel.InstType.Normal);调用:当调用到第二个时就出现异常了,因为首个委托需要三个参数,而第二次调用只要一个参数,所以就出现了索引不存在的异常。因为首个编译的委托需要三个参数。这也就是我所说的,你只缓存了首个调用的构造信息委托。即使第二次不同的构造参数的上下文 Key 也与第一个相同才导致这个结果。var factory = Factory.GetInst(); var o1 = factory.Get<IOrders>("a", 1, "张三", 9.0); var o2 = factory.Get<IOrders>("a", 1); //产生异常 if (o2 != null)
{
}其实要实现不仅仅是参数。
如具有如下构造,并且都能够识别出相关的构造调用,如果性能仍然是前者的 5 倍,那就很不错了。 [code=csharp]
public class U
{
public int User { get; set; }
} public class U1:U
{
public string Id { get; set; }
} public class Abc
{
public Abc(int a, string b)
{
}
public Abc(string a, int b, string c)
{
}
public Abc(int a, string b, string c)
{
}
public Abc(int a, string b, int? c)
{
}
public Abc(int a, U u)
{
} public Abc abc(params object[] args)
{
//args 要能正确处理参数并解析调用哪个造构的委托。 return new Abc(1, (string)null); return new Abc(1, (U)null); return new Abc(1, new U1()); //U1继承U return new Abc(null, 1, ""); return new Abc(1, null, (string)null); return new Abc(1, null, (int?)null); //Nullable<int> 与 int }
}[/code]
System.Activator.CreateInstance(typeof(User), 1, 3, 5);
这个也只找到匹配最高的。
A类可以用2参构造
B类可以用5参构造
但是A类不能用了2参又用1参。因为我这里不支持。也没有必要支持
因为2参就可以包含1参,并且你在DI的时候只可能用到其中一个构造,不可能同时在DI中一会用这个构造一会用另外一个构造。
我们用IOC的目的是什么?是实现实例化的控制反转以及依赖注入。
所以我们比较的肯定是实例化相同数量的实例,谁快必然谁的性能高。
我是做自己的IOC容器,又不是说Copy的Untiy的IOc容器。我有些东西为什么就一样要完全的Untiy一样呢?
何况多一个多构造的支持也并没有增加多少复杂度。我只是认为没有必要而已。
如果说比较过程的话,
A点到B点,从直线来说有2种方法。
1、A正方向到B.
2、A反方向绕地球到C后再从C到B。
按照你的所谓复杂度不一样没有可比性来说,
第一种方法和第二种方法因为复杂度不一样。
所以1方法和2方法的从A到B的速度方面没有可比性。