zoukankan      html  css  js  c++  java
  • 对Castle Windsor的Resolve方法的解析时new对象的探讨

    依赖注入框架Castle Windsor从容器里解析一个实例时(也就是调用Resolve方法),是通过调用待解析对象的构造函数new一个对象并返回,那么问题是:它是调用哪个构造函数呢?

    • 无参的构造函数
    • 带参但参数不是靠依赖注入的构造函数
    • 带参且参数是靠依赖注入的构造函数
    • 有多个带参且参数是靠依赖注入的构造函数

    带着这个问题,我写了一段测试代码.

    测试1:

    只有一个无参构造函数:

    CtorTest类(在控制台程序里用Windsor解析这个类)

       public class CtorTest
        {
    
           public string Message { get; set; }
    
            public CtorTest()
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }
    
            public void ShowMessage()
            {
                Console.WriteLine(Message);
            }
        }

    控制台Main代码如下所示:

    class Program
        {
            static void Main(string[] args)
            {
                IWindsorContainer iocContainer = new WindsorContainer();
                iocContainer.Register(Component.For<CtorTest>().ImplementedBy<CtorTest>().LifestyleSingleton());
                
                var instance = iocContainer.Resolve<CtorTest>();
                instance.ShowMessage();
            }
        }

    测试结果(默认构造函数与无参构造函数性质是一样的):

    测试2

    只有一个带参但不是靠依赖注入的构造函数(没有无参数构造函数)

    CtorTest代码如下:

     public string Message { get; set; }
    
            public CtorTest(string message)
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }
    
            public void ShowMessage()
            {
                Console.WriteLine(Message);
            }
        }

    测试结果,当然是抛出异常:

    如果为这个参数提供默认值(如:string message=""),Resolve会调用这个构造函数,如果再加一个无参构造函数,Resolve会调用带参的,如再加一个带有两个带默认值的带参构造函数,则会调用两个参数的,所以这里的结论是:带有默认值的有参(先参数个数多的),再无参.

    测试3:

    有一个带参且参数是靠依赖注入的构造函数,和一个无参数构造函数,一个两个具有默认值参数的构造函数.

    添加一个Sub类:

        public class Sub
        {
            public string Message { get; set; }
    
            public Sub()
            {
                Message = $"The message is from {nameof(Sub)}";
            }
        }

    Ctor类代码如下:

      public class CtorTest
        {
    
           public string Message { get; set; }
    
            public CtorTest()
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }

          public CtorTest(string message = "message1",string message2= "message2")
          {
            Message = $"The message is from {nameof(CtorTest)} and {message} and {message2}" ;
          }

    public CtorTest(Sub sub)
            {
                Message = sub.Message;
            }
    
            public CtorTest(string message = "")
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }
    
            public void ShowMessage()
            {
                Console.WriteLine(Message);
            }
        } 

    Main如下:

    class Program
        {
            static void Main(string[] args)
            {
                IWindsorContainer iocContainer = new WindsorContainer();
                iocContainer.Register(Component.For<CtorTest>().ImplementedBy<CtorTest>().LifestyleSingleton());
           //把sub注入到容器中 iocContainer.Register(Component.For<Sub>().ImplementedBy<Sub>().LifestyleSingleton()); var instance = iocContainer.Resolve<CtorTest>(); instance.ShowMessage(); } }

     测试结果:

    从结果可以看出它是通过带参(参数是依赖注入)的构造函数创建实例,即使在有一个2个具有默认值的参数的构造函数的情况下.

    测试4

    两个带参且参数是靠依赖注入的构造函数

    添加一个Sub2类:

        public class Sub2
        {
            public string Message { get; set; }
    
            public Sub2()
            {
                Message = $"The message is from {nameof(Sub2)}";
            }
        }

    Ctor类代码如下:

        public class CtorTest
        {
    
            public string Message { get; set; }
    
            public CtorTest()
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }
    
            //注意:我故意把这个放到sub参数的构造函数前面
            public CtorTest(Sub2 sub2)
            {
                Message = sub2.Message;
            }
    
    
            public CtorTest(Sub sub)
            {
                Message = sub.Message;
            }
    
            public CtorTest(string message = "")
            {
                Message = $"The message is from {nameof(CtorTest)}";
            }
    
            public void ShowMessage()
            {
                Console.WriteLine(Message);
            }
        }

    Main类代码如下:

        class Program
        {
            static void Main(string[] args)
            {
                IWindsorContainer iocContainer = new WindsorContainer();
                iocContainer.Register(Component.For<CtorTest>().ImplementedBy<CtorTest>().LifestyleSingleton());
           //把sub2注入到容器中,注意我故意把sub2放到sub前面 iocContainer.Register(Component.For<Sub2>().ImplementedBy<Sub2>().LifestyleSingleton()); //把sub注入到容器中 iocContainer.Register(Component.For<Sub>().ImplementedBy<Sub>().LifestyleSingleton()); var instance = iocContainer.Resolve<CtorTest>(); instance.ShowMessage(); } }

    测试结果:

    尽管我把Sub2的构造函数和注册都放在了Sub前面,但最终还是调用了带Sub参数的构造函数.那么它的顺序是什么呢?通过修改类的名称(比如说把Sub2改成排序在Sub前的名称,如S,那么就会调用S这个参数的构造函数)

    测试5

    有两个带参且参数是靠依赖注入的构造函数

    把CtorTest类里的

            public CtorTest(Sub2 sub2)
            {
                Message = sub2.Message;
            }

    修改成

            public CtorTest(Sub2 sub2,Sub sub)
            {
                Message = sub2.Message +Environment.NewLine + sub.Message; 
            }

    测试结果:

    它调用的是修改后的这个构造函数,也就是说:它先调用了参数多的那个.

    最终总终:

    Resolve先调用参数个数多且参数通过依赖注入的构造函数,如果参数个数相同的构造函数有多个,则按参数类型名称(这个名称应该是完全限定名,没有测试)顺序,调用第一个,如果不存在这样的构造函数,则优先调用参数个数多且具有默认值的构造函数.

  • 相关阅读:
    Spring自动装配Beans
    Spring过滤器组件自动扫描
    Spring自动扫描组件
    Spring EL运算符实例
    Spring EL方法调用实例
    Spring EL bean引用实例
    Spring EL hello world实例
    Spring @PostConstruct和@PreDestroy实例
    Spring Bean init-method 和 destroy-method实例
    Spring Bean InitializingBean和DisposableBean实例
  • 原文地址:https://www.cnblogs.com/kid1412/p/6246588.html
Copyright © 2011-2022 走看看