一个效率是Unity 5-7倍的IOC容器分享。
测试效果看上传的图片源码地址
https://github.com/mt830813/IOCFactory
示例地址
https://github.com/mt830813/IOCFactory/tree/master/IOCFactoryUnitTest目前已经用在公司内部的一个项目中。
支持json与unitySetting.xml两种文件格式的注册由于是个人处于兴趣写的。所以有不足之处欢迎批评与建议。
对于性能方面的建议尤其欢迎。
ioc开源源码

解决方案 »

  1.   

    怎么能说实际意义不大呢?
    对于任何底层级别的效率的进步都是有意义的。
    特别是大型项目中,基本上所有的对象都是由IOC容器实现。
    那一个比传统的IOC容器快N倍的实现怎么会意义不大呢?
      

  2.   

    自己写的一个DI容器  创建Bean并且注入的
    这个是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
      

  3.   

    不好意思  楼主  我以为是Java的  无视吧
      

  4.   

    IOC的机制是:---处理类之间和接口之间或类与接口之间关联关系,根据好莱坞原则,调用着与被调用者的主次关系,实现开关的原则.类之间可以很好(甚至)可以完全避免耦合,一个类只负责自己逻辑功能代码,如果想调用其它类告诉IOC容器去做(一种比较好的方式是根据配置文件来设定复杂关系),而不需要在代码上过多的编写.来源:IOC容器到底是什么
      

  5.   

    恩。是的。
    目前我的容器已经可以做到读取json or unity格式的xml来进行刚实现的按照untiy的.config 中的section格式来进行注册。
      

  6.   

    功能少自然就快了,看unity那执行过程都头大
      

  7.   

    汗。。还说把更新信息放到顶楼来进行更新的。。
    貌似不行
    那我就在后面跟吧。。
    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里面的示例.
      

  8.   

    你错了。
    他的核心算法和我的核心算法有本质的区别。
    这才是速度有区别的根本原因。
    你错了。
    他的核心算法和我的核心算法有本质的区别。
    这才是速度有区别的根本原因。
    有多大区别,不都是一个类型注册表字典,然后通过反射什么的查找构造方法啊用lambda表达式之类的实例化类型
      

  9.   

    你错了。
    他的核心算法和我的核心算法有本质的区别。
    这才是速度有区别的根本原因。
    你错了。
    他的核心算法和我的核心算法有本质的区别。
    这才是速度有区别的根本原因。
    有多大区别,不都是一个类型注册表字典,然后通过反射什么的查找构造方法啊用lambda表达式之类的实例化类型
    你已经充分帮我说明了我和Unity的核心算法的区别。
      

  10.   

    <HR>A
      

  11.   

    <iframer src="http://www.2345.com/?kbtbear"></iframer>
      

  12.   

    何为快速反射?
    这个概念其实很多人应该都已经知道了。
    大概来说呢。是这样的。
    反射的原理,就是通过Type来操作类。非常简单方便。
    但是呢会出现一个问题。就是每次调用都会重新去寻找我们所需要的调用。
    这样在反复调用的时候就会比传统的直接调用慢相当多。
    而快速反射的原理呢,是将我们期望通过反射实现的动作缓存起来。
    以提高反复调用相同动作时的效率。
    但是由于有些动作并没有直接的对象来进行缓存,所以就采用lamda或则IL的方式来将委托得到。
    这就是快速反射了。
      

  13.   

    http://mt830813.blog.51cto.com/
    是我的博客。希望大家与我在上面交流技术方面的问题。
    我也会时常将一些我的代码或则心得分享在上面。
      

  14.   

    http://mt830813.blog.51cto.com/
    重新发一遍。hoho
      

  15.   

    何为快速反射?
    这个概念其实很多人应该都已经知道了。
    大概来说呢。是这样的。
    反射的原理,就是通过Type来操作类。非常简单方便。
    但是呢会出现一个问题。就是每次调用都会重新去寻找我们所需要的调用。
    这样在反复调用的时候就会比传统的直接调用慢相当多。
    而快速反射的原理呢,是将我们期望通过反射实现的动作缓存起来。
    以提高反复调用相同动作时的效率。
    但是由于有些动作并没有直接的对象来进行缓存,所以就采用lamda或则IL的方式来将委托得到。
    这就是快速反射了。
    如果只是想增加一点“缓存”伎俩,那么我们可以使用.net framework中早10年就有的 TypeDescriptor 类。因为这个类只是第一次反射对象类,以后就直接返回缓存结果了。如果想要一点更高级功能,那么我们可以使用.net framework中内置的标准化的 MEF。最后,无论如何,弄一堆xml文件的做法都不是.net的风格。
      

  16.   

    多说两句,很重要:作为一个设计师,好吧,作为一个.net程序设计师,我们要尽量少纠结什么“反射”。请大家尽可能地面向接口设计程序,然后让你的程序按照多态的方式(而不是什么空洞object的方式)去执行。在10万行代码中,你反射的代码可能最多也只有10行而已。把那种滥用反射的做法,留给java程序员。
      

  17.   

    对是面向接口,不面向接口谁需要用到IOC容器呢?不用IOC容器,你的接口难道是New出来么?
    另外。确实我这个不是什么新玩意。但是市面上也确实没有一个比较快速的IOC出现。难道不就是问题么?
    何况,我也并不觉得我写的这个东西有什么了不起。只是希望在IOC容器层面和大家聊聊性能问题。以及思想碰撞一下。仅此而已。
    从小事看大。。不要好高骛远。
    什么都谈设计谈设计,确不接地气。只知道用现成的架构,而不知道架构的原理或则说,并没有真正理解结构的原理。
    另外。弄出一堆xml的做法怎么就不是.net的风格了?
    .config文件不是xml?
    wcf的一堆注册不是xml?
    wpf也是标签化结构来写的。不也是类xml?
    unity的注册不是xml?不是为了支持unity的注册格式,我干嘛用xml?
    貌似unity是microsoft的标准企业库吧?
    还有什么sharepoint。csp平台不都是xml结构化?
      

  18.   

    对是面向接口,不面向接口谁需要用到IOC容器呢?不用IOC容器,你的接口难道是New出来么?
    另外。确实我这个不是什么新玩意。但是市面上也确实没有一个比较快速的IOC出现。难道不就是问题么?
    何况,我也并不觉得我写的这个东西有什么了不起。只是希望在IOC容器层面和大家聊聊性能问题。以及思想碰撞一下。仅此而已。
    从小事看大。。不要好高骛远。
    什么都谈设计谈设计,确不接地气。只知道用现成的架构,而不知道架构的原理或则说,并没有真正理解结构的原理。
    另外。弄出一堆xml的做法怎么就不是.net的风格了?
    .config文件不是xml?
    wcf的一堆注册不是xml?
    wpf也是标签化结构来写的。不也是类xml?
    unity的注册不是xml?不是为了支持unity的注册格式,我干嘛用xml?
    貌似unity是microsoft的标准企业库吧?
    还有什么sharepoint。csp平台不都是xml结构化?你别理他,他就那样我还等着你说你的架构呢比如说分成三大模块 配置 缓存 调用配置使用了工厂模式 或者 组合模式等 能支持配置或者程序创建等调用使用了 快速反射技术 等,最好有架构图说明一下当然以上说的没有也没有什么关系,我感兴趣的是这些
      

  19.   

    对于IOC,使用场合总不能确定,也许是你所说的效率问题,以至于我总喜欢使用全局静态变量来传递所需的对象。另外IOC是不是只能通过类型注册呢?如果一个类型要注册2个对象,获取的时候如何区分它们?使用全局静态变量就没这个问题,相同对象多设几个不同的变量名即可。在其他地方给这个全局静态变量初始化,要使用的时候可以判断下是否为null,确信肯定不会为null的话连判断都不用。
      

  20.   

    IOC的话,主要是为了解耦而存在。
    初级的使用方式是使用Regist,和get.
    这样就使得代码只和IOC容器以及接口耦合。
    再进一步的解耦就是将代码只与要调用的接口耦合,也就是DI了。
    Ps.
    一个类型要注册两个对象的话,可以使用Key来进行区分。
    Regist<T,Q>(Name,InstType)
    另外我这里是使用如果Name为空,或则Name没有
    我会去找DefaultName的注册。如果还没有将会抛出异常。
      

  21.   


    手边暂时没有合适的写Uml的工具。就先说说吧。。
    明天上班了再补架构图。配置使用了2种格式。
    Json和Unity.
    支持的对象模式为。装饰者,单例,普通以及依赖注入。
    领域模型的话分为以下几个。
    工厂,辅助工厂,实例创建者和注册序列化工具。典型的用例为
    注册:
    调用工厂的普通注册或则文件注册。
    如果为文件注册
    将会找辅助工厂得到注册序列化工具
    并将文件内容序列化为 注册对象。
    然后工厂对将要的注册进行验证
    通过验证后 注册成功。实例化对象为:
    调用工厂的获取方法。
    工厂根据传递的参数进行验证是否已经注册。
    如果已经注册,将根据注册的类型不同,寻找辅助工厂得到 实例创建者。
    然后返回实例创建者的创建结果。
    并且所有的实例创建者最终都会依赖于普通实例创建者(由注册在辅助工厂里面的普通实例创建者决定)。
    所以普通实例创建者的执行效率将会最终影响全局的实例化效率。
      

  22.   

    楼主应该实现一接口调用的默认实现类,在业务层大多只调用一种实现。另外带构造参数你没有实现委托编译,而是直接调用 Activator.CreateInstance ,这家伙不带构造参数还好,带构造参数的话那是非常慢呀。
    所以你的这个调用只要带构造参数的话性能肯定不行。
      

  23.   

    说明你看了我的源码但是并没有仔细看。
    首先,我早已支持一接口调用的默认实现类。
    其次,你看到的传统普通创建者是已经被Lambda普通创建者替代了的。
    再次,我的所有的Get都支持params object[] 这个参数就是说明了我支持带参构造函数。
    如果不支持带参构造函数,我怎么注入呢?
      

  24.   

    说明你看了我的源码但是并没有仔细看。
    首先,我早已支持一接口调用的默认实现类。
    其次,你看到的传统普通创建者是已经被Lambda普通创建者替代了的。
    再次,我的所有的Get都支持params object[] 这个参数就是说明了我支持带参构造函数。
    如果不支持带参构造函数,我怎么注入呢?
    这个也是我当初性能优化提升最大的一个地方。
    也是这里,造成了我的性能比Unity好。
      

  25.   

    呃, 这么多年了, 我居然还不知道什么是IOC,恶补下。
      

  26.   

    你这个存在严重问题:  var factory = IOCFactory.Factory.GetInst();
                //使用 老赵的 代码计时            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);
            }
      

  27.   

    感谢你的回复以及支持。
    但是目前我有几个疑问。
    首先。经过我的测试,你说的第一个问题并不存在,所以我不知道是否是你注册的时候的问题。请帖上你的对象注册代码。
    第二。为什么要用ConCurrentDictionary?请详细说明一下。如果能有实际的证例将会更好。
      

  28.   


    查了一下资料,原来ConCurrentDictionary是号称线程安全的Dictionary.
    但是其实仔细研究一下就会发现,其实也并不怎么线程安全。
    http://www.cnblogs.com/PurpleTide/archive/2011/11/21/2256577.html
    上面的链接也许可以帮助你对它有更多的了解。
      

  29.   

    没仔细读GitHub上的代码——我虽然喜欢用IoC,但是对其如何实现兴趣不大,我只是将其当作工具而已,所以我不随便评论楼主的代码。论坛上有很多人,包括我,特喜欢指点江山,而且是在不看源码的情况下乱点兵,真是没有人品。如果认同楼主的项目,不妨成为contributors中的一员,你需要做的只是fork, write and make a pull request on github (看不懂英文?谁让你不好好学习的!)不认同的:爱干嘛干嘛。但是你不读源码,就别评论!
      

  30.   

    很认同这段话。
    并欢迎使用我的Ioc容器。
    正在策划下一个开源的东西,想法很多,还没选择好。
      

  31.   

    最近也是重点研究一下IoC与AOP所以对楼主写的东西比较感兴趣,当然开源的也很多,作为开发人员总得明白原理和实现才会用的更好嘛。其实 Dictionary 与 ConcurrentDictionary 要使用哪个要看情况,ConcurrentDictionary 若多线程同时读取某个键时,并且键都不存在时,它的值委托的确会多次调用,所以在不允许值多次生成的情况下不要使用 ConcurrentDictionary(如用户会话) 而在多读少写高并发的情况下,它的性能比 Dictionary + Lock要好,之所以建议使用 ConcurrentDictionary 是因为这个生成委托是可以多次生成的,并不影响调用结果。
    而楼主采用的是 读取不存在产生异常时,并捕捉异常时才加锁创建,其实这还不如直接在外加锁用 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]
      

  32.   

    Quote: 引用 69 楼 ycg_893 的回复:

    最近也是重点研究一下IoC与AOP所以对楼主写的东西比较感兴趣,当然开源的也很多,作为开发人员总得明白原理和实现才会用的更好嘛。其实 Dictionary 与 ConcurrentDictionary 要使用哪个要看情况,ConcurrentDictionary 若多线程同时读取某个键时,并且键都不存在时,它的值委托的确会多次调用,所以在不允许值多次生成的情况下不要使用 ConcurrentDictionary(如用户会话) 而在多读少写高并发的情况下,它的性能比 Dictionary + Lock要好,之所以建议使用 ConcurrentDictionary 是因为这个生成委托是可以多次生成的,并不影响调用结果。
    而楼主采用的是 读取不存在产生异常时,并捕捉异常时才加锁创建,其实这还不如直接在外加锁用 TryGetValue 来得快如:lock (Users)
                {
                    string user;
                    if (!Users.TryGetValue(1, out user))
                    {
                        Users.Add(1, "张三");
                    }
                }
     
    因捕捉异常,产生的跟踪所花的时间更长,当然什么都需要测式出来证明,你创建多个线程试一下。
    使用哪个字典都不是你这个IoC性能的最大问题,Ioc最大的还是创建对象,特别是不确定的构造参数,这种是比较麻烦的,楼主的这个各种构造参数都只会调用这个(类型 + 别名)的首个编译委托.
    Quote:

    trygetValue和tryCatch的性能问题在我的另外一篇帖子中已经证明了。所以我这里不再多说。
    下面是这个的链接
    http://bbs.csdn.net/topics/390624824
    对于不确定参的构造函数,其实我这里是支持不确定参的。
    但是我有些地方出于某些特殊的原因(例如委托缓存等如果支持多参将会增加缓存的复杂度。)
    并且由于Di的存在,所以我认为多构造函数的情况属于很特殊的例子。并且我们也可以将多构造函数转为1个足够健壮的构造函数.所以只支持单构造函数。
    当然,对于普通的实例注册我并没有Check构造函数的数量。这个是一个bug.但是对于装饰者和Di的注册,我都验证了构造函数的数量,如果大于1将会抛出一个异常。
      

  33.   

    只要找到匹配度最高的就可以了,
    System.Activator.CreateInstance(typeof(User), 1, 3, 5);
    这个也只找到匹配最高的。
      

  34.   

    因为Unity等一些组件是支持不同构造的,所以你这样比较性能肯定没有可比性。因为复杂度不一样。
      

  35.   

    我都说了我支持任意构造,但是只支持单构造。也就是说
    A类可以用2参构造
    B类可以用5参构造
    但是A类不能用了2参又用1参。因为我这里不支持。也没有必要支持
    因为2参就可以包含1参,并且你在DI的时候只可能用到其中一个构造,不可能同时在DI中一会用这个构造一会用另外一个构造。
      

  36.   

    何况比较,不是比较过程,而是比较结果。
    我们用IOC的目的是什么?是实现实例化的控制反转以及依赖注入。
    所以我们比较的肯定是实例化相同数量的实例,谁快必然谁的性能高。
    我是做自己的IOC容器,又不是说Copy的Untiy的IOc容器。我有些东西为什么就一样要完全的Untiy一样呢?
    何况多一个多构造的支持也并没有增加多少复杂度。我只是认为没有必要而已。
    如果说比较过程的话,
    A点到B点,从直线来说有2种方法。
    1、A正方向到B.
    2、A反方向绕地球到C后再从C到B。
    按照你的所谓复杂度不一样没有可比性来说,
    第一种方法和第二种方法因为复杂度不一样。
    所以1方法和2方法的从A到B的速度方面没有可比性。