zoukankan      html  css  js  c++  java
  • Castle学习笔记之Windsor(二)

    最近琐事繁多,以至于这个系列的第二篇文章都迟迟未出,-_-!!
    今天特定花点时间来完成它.

    我们接着上篇进行一些深入的分析.
    首先是构造注入,在Windsor中,我们获取的一个对象实例的代码大致如下:
    IWindsorContainer container = new WindsorContainer("../../test.xml");
    container.AddComponent(
    "test"typeof(TestObj));
    TestObj obj 
    = (TestObj)container["test"];

    配置文件如下:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <components>
        
    <component id="test">
          
    <parameters>
            
    <key>key</key>
          
    </parameters>
        
    </component>
      
    </components>
    </configuration>

    具体上面的代码是什么意思,在上篇文章已经写的比较清楚了,这里就不再多说,现在我们开始分析,为什么只是单单的一个AddComponent就可以直接获取对象实例了.

    很自然的,我们从AddComponent函数入手分析.在Container里只有简单的:_kernel.AddComponent
    看来这只是层很浅显的封装,关键操作始终是要在kernel里进行.转入DefaultKernel,因为这里的_kernel只是个接口,从WindsorContainer的默认构造函数:

            public WindsorContainer() : this(new DefaultKernel(), new Installer.DefaultComponentInstaller())
            
    {
            }

    可以很容易看出该接口的实例是个DefauleKernel对象.
    进入它的AddComponent函数查看,发现只有几行子代码,又是封装.在大型的框架里,为了保持整体结构的完整即使一个很小的功能也会有若干层嵌套,这会给设计者以后的扩展提供便利同时也会给学习者增加难度,我们就耐着性子一步步往下看吧:)

            public virtual void AddComponent(String key, Type classType)
            
    {
                
    if (key == nullthrow new ArgumentNullException("key");
                
    if (classType == nullthrow new ArgumentNullException("classType");

                ComponentModel model 
    = ComponentModelBuilder.BuildModel(key, classType, classType, null);
                RaiseComponentModelCreated(model);
                IHandler handler 
    = HandlerFactory.Create(model);
                RegisterHandler(key, handler);
            }

    这里包含了许多信息,不过我们只关注组件创建时的构造函数的参数如何注入,因此我们分析ComponentModel那句.
    这里面出现的ComponentModelBuilder派生自IComponentModelBuilder接口,所有的组件模型构造器都必须从该接口派生,其本身包含了AddContribuitor,RemoveContribuitor和BuildModel方法.这里的ComponentModelBuilder是DefaultComponentModelBuilder的实例对象,除了上述的三个方法外,还额外的添加了InitializeContributors方法用于添加默认的Contributors.该方法如下:

                    protected virtual void InitializeContributors()
            
    {
                AddContributor( 
    new ConfigurationModelInspector() );//
                AddContributor( new LifestyleModelInspector() );
                AddContributor( 
    new ConstructorDependenciesModelInspector() );
                AddContributor( 
    new PropertiesDependenciesModelInspector() );
                AddContributor( 
    new MethodMetaInspector() );
                AddContributor( 
    new LifecycleModelInspector() );
                AddContributor( 
    new ConfigurationParametersInspector() );
                AddContributor( 
    new InterceptorInspector() );
            }

    这里我们只关心AddContributor( new ConstructorDependenciesModelInspector() );也就是构造函数依赖的处理.
    这句把该模块的处理加入到contributors队列中.返回到BuildModel函数,出现了我们希望看到的关键性代码:

                foreach(IContributeComponentModelConstruction contributor in contributors)
                
    {
                    contributor.ProcessModel( kernel, model );
                }

    以前已经说了,构造函数依赖关系的处理已经被加入contributors队列,接下来,我们开始进入ConstructorDependenciesModelInspector的ProcessModel方法进行分析.

            public virtual void ProcessModel(IKernel kernel, ComponentModel model)
            
    {
                
    if (converter == null)
                
    {
                    converter 
    = (ITypeConverter) 
                        kernel.GetSubSystem( SubSystemConstants.ConversionManagerKey );
                }


                Type targetType 
    = model.Implementation;

                ConstructorInfo[] constructors 
    = 
                    targetType.GetConstructors(BindingFlags.Public
    |BindingFlags.Instance);

                
    foreach(ConstructorInfo constructor in constructors)
                
    {
                    
    // We register each public constructor
                    
    // and let the ComponentFactory select an 
                    
    // eligible amongst the candidates later

                    model.Constructors.Add( CreateConstructorCandidate(constructor) );
                }

            }


    终于看到了熟悉的反射!函数本身结构很清晰,首先取出所有的构造函数,然后循环,同时给ConstructorCandidate对象赋值,这是个包含了构造信息和依赖模块的对象(该对象包含了构造函数的参数信息).

    到此为止,组件的添加过程中与构造函数参数注入有关的部分就结束了,虽然有了个轮廓,但是关键的注入部分始终还没出现,别急,我们接着往下看:)
    我们直接返回到最前端,TestObj obj = (TestObj)container["test"];将真正的创建实例,这之前,TestObj对象一直都是处于未激活状态.继续trace…
    容器的索引直接被指向_kernel的索引,

            public virtual object this[String key]
            
    {
                
    get
                
    {
                    
    if (key == nullthrow new ArgumentNullException("key");

                    
    if (!HasComponent(key))
                    
    {
                        
    throw new ComponentNotFoundException(key);
                    }


                    IHandler handler 
    = GetHandler(key);

                    
    return ResolveComponent(handler);
                }

            }

    激活的关键就在ResolveComponent函数,进入后才发现,需要转入DefaultHandler的Resolve进行处理,当依赖条件满足时即创建对象所依赖的对象是否都已经激活时,将进入生命周期管理器的Resolve函数进行处理.接下来的调用关系比较复杂,我简单描述一下调用关系:
    AbstractLifestyleManager.Resolve()->IComponentActivator.Create()->派生自AbstractComponentActivator的某类->InternalCreate()->Instantiate()
    这里停下来了,因为最关键的注入就在这里了,我们开始仔细分析

            protected virtual object Instantiate()
            
    {
                ConstructorCandidate candidate 
    = SelectEligibleConstructor();
        
                Type[] signature;
                
    object[] arguments = CreateConstructorArguments( candidate, out signature );
        
                
    return CreateInstance(arguments, signature);
            }

    首先是取出之前生成的ConstructorCandidate对象,然后进入CreateConstructorArguments函数,从下面的返回我们已经可以断定注入就在这个函数里.
    CreateConstructorArguments

            protected virtual object[] CreateConstructorArguments( ConstructorCandidate constructor, out Type[] signature )
            
    {
            
    //
                foreach(DependencyModel dependency in constructor.Dependencies)
                
    {
                    
    object value = Kernel.Resolver.Resolve(Model, dependency);
                    arguments[index] 
    = value;
                    signature[index
    ++= dependency.TargetType;
                }


                
    return arguments;
            }


    里面我省略了些代码,关键的部分就是这个循环,由object value = Kernel.Resolver.Resolve(Model, dependency);取出了指定的依赖参数的值,生成数组返回,最后CreateInstance…
    终于看到了对象的实例化,构造函数的注入的过程已经全部清晰了!
    在使用Windsor的容器注册并消除耦合的简单之下,却隐藏着如此深刻的背景,Castle的结构的复杂可见一斑…

    到这,本来还想继续介绍些组件的注册方式和参数的配置问题,不过发现本篇的篇幅已经够长了,-_-!,那就留到下篇再写吧:)

    PS:说几句题外话,在该系列的第一篇文章里,有朋友问到Castle的性能问题,我想说的是,您看完这篇文章,应该心中就有数了吧?大型的框架专注的是企业级应用和快速开发,如果您的项目需要非常短的响应时间,那么这种类型的框架往往都是不适应的,当然,Castle本身的优秀是不容置疑的,只不过各种框架都有其适用的范围和方向,我们在开发中一定要根据实际情况来判断使用何种方式.(为了写这篇文章,加班了半小时啊,各位看完的朋友一定多多提意见那)

  • 相关阅读:
    由基于qml,c++的串口调试工具浅谈qml与c++混合编程
    qt5_qml_Opengl_shader 第一弹----------------------openglunderqml的简化及介绍
    Delphi 的接口机制——接口操作的编译器实现过程(2)
    Delphi 的接口机制——接口操作的编译器实现过程(1)
    ddd
    [leetcode]Gray Code
    synapse socket总结一:服务器模型
    CentOS 6.5(64bit)安装GCC4.8.2+Qt5.2.1(替换GCC的链接库)
    Qt打开外部程序和文件夹需要注意的细节(Qt调用VC写的动态库,VC需要用C的方式输出函数,否则MinGW32编译过程会报错)
    Qt+SQLite数据加密的一种思路(内存数据库)
  • 原文地址:https://www.cnblogs.com/wuxilin/p/387756.html
Copyright © 2011-2022 走看看