Castle学习笔记之Windsor(二)
今天特定花点时间来完成它.
我们接着上篇进行一些深入的分析.
首先是构造注入,在Windsor中,我们获取的一个对象实例的代码大致如下:
container.AddComponent("test", typeof(TestObj));
TestObj obj = (TestObj)container["test"];
配置文件如下:
<configuration>
<components>
<component id="test">
<parameters>
<key>key</key>
</parameters>
</component>
</components>
</configuration>
具体上面的代码是什么意思,在上篇文章已经写的比较清楚了,这里就不再多说,现在我们开始分析,为什么只是单单的一个AddComponent就可以直接获取对象实例了.
很自然的,我们从AddComponent函数入手分析.在Container里只有简单的:_kernel.AddComponent
看来这只是层很浅显的封装,关键操作始终是要在kernel里进行.转入DefaultKernel,因为这里的_kernel只是个接口,从WindsorContainer的默认构造函数:
{
}
可以很容易看出该接口的实例是个DefauleKernel对象.
进入它的AddComponent函数查看,发现只有几行子代码,又是封装.在大型的框架里,为了保持整体结构的完整即使一个很小的功能也会有若干层嵌套,这会给设计者以后的扩展提供便利同时也会给学习者增加难度,我们就耐着性子一步步往下看吧:)
{
if (key == null) throw new ArgumentNullException("key");
if (classType == null) throw 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.该方法如下:
{
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函数,出现了我们希望看到的关键性代码:
{
contributor.ProcessModel( kernel, model );
}
以前已经说了,构造函数依赖关系的处理已经被加入contributors队列,接下来,我们开始进入ConstructorDependenciesModelInspector的ProcessModel方法进行分析.
{
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的索引,
{
get
{
if (key == null) throw 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()
这里停下来了,因为最关键的注入就在这里了,我们开始仔细分析
{
ConstructorCandidate candidate = SelectEligibleConstructor();
Type[] signature;
object[] arguments = CreateConstructorArguments( candidate, out signature );
return CreateInstance(arguments, signature);
}
首先是取出之前生成的ConstructorCandidate对象,然后进入CreateConstructorArguments函数,从下面的返回我们已经可以断定注入就在这个函数里.
CreateConstructorArguments
{
//
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本身的优秀是不容置疑的,只不过各种框架都有其适用的范围和方向,我们在开发中一定要根据实际情况来判断使用何种方式.(为了写这篇文章,加班了半小时啊,各位看完的朋友一定多多提意见那)