曾几何时,从Spring中认识了IoC这个词语,但它并没有撩动我的心,原因很简单,我懵懂年代的程序连个静态Factory来创建实例都显得有点多余,Ioc更没有登场的必要。真正认识IoC也许是在使用Castle的时候,记得印象最深刻的一个情景是,我们团队当时的BS项目,开始设计时使用了一个第三方组件,后来需求变动了,这个第三方组件的功能却跟不上需求,我们不得不要换用一个新的组件,但是项目已经部署,客户要求更新后如果出问题能自行恢复到旧版本,当时想到一个笨拙的方法是,要求客户备份一下程序,然后出问题覆盖之就可以了,但是这样有个个问题,新开发模块和维护模块是同时进行部署的,怎能保证同一个模块中一部分使用新的程序,而一部分要恢复到旧程序中去呢,显然在旧办法中不重新编译就达不到这个要求,而其中即使有良好的版本控制,也是一两个文件Undo就能了事的,幸好这时Windsor跳进了我们的视线,使用它通过配置文件实现组件的自由设换,帮助我们轻松度过难关。这虽然不是一个应用IoC的正途例子,却在实际中帮了我们大忙^_^,要想正统的了解IoC,就要重温Martin Fowler大叔的经典文章《Inversion of Control Containers and the Dependency Injection pattern 》中文版 随着P&P团队发布Entlib 4.0 的蓝图,Unity 慢慢映入我的眼帘,又是一个轻量级的IoC,现在终于发布了1.0版本,到底性能如何,让我们先看看附带的StopLight QuickStart
1.在代码中注册对象的映射 代码如下:
IUnityContainer container
=
new
UnityContainer() .RegisterType
<
ILogger, TraceLogger
>
() .RegisterType
<
IStoplightTimer, RealTimeTimer
>
();
//
为容器注册默认注入实例
Application.Run(container.Resolve
<
StoplightForm
>
());
基本的流程是:创建注入容器 => 注册对象映射 => 调用对象时根据映射关系创建对象 在这个QuickStart中创建对像具体的流程是 StoplightForm -》StoplightPresenter -》Stoplight -》ILogger -》TraceLogger -》StoplightSchedule -》IStoplightTimer -》RealTimeTimer -》ILogger(有重复的话,会检查是否已经曾经实例化过,如果有,找出所使用实例化的策略去实例化或者不重新实例化(单件模式)) 在要实例化接口的地方使用Dependency属性,如(这里使用属性来做关联处理,对调试造成一定的麻烦,使用Unity时可能会在这里跟踪代码丢失的问题,唯一解决的办法就是直接使用Unity的源码嵌套到项目中进行使用 ^_^)
[Dependency]
public
ILogger Logger
...
{ get ... { return logger; } set ... { logger = value; } }
具体在Unity里面的是实现是
public
object
Resolve(IBuilderContext context)
//
IBuilderContext : 包含要生成父对象的构建信息
...
{ Guard.ArgumentNotNull(context, " context " ); NamedTypeBuildKey key = new NamedTypeBuildKey(type, name); IBuilderContext recursiveContext = context.CloneForNewBuild(key, null ); // 根据注册关联的信息按照响应的实例策略一层一层实例化 return recursiveContext.Strategies.ExecuteBuildUp(recursiveContext); }
同一接口也可以注册多个实例 如添加一个实现类
internal
class
MakeFunLogger : ILogger
...
{ ILogger Members #region ILogger Members public void Write( string message) ... { Trace.WriteLine( string .Format( " {0}: {1} " , DateTime.Now, message + " ,与Windsor相比,Unity仍需努力 " )); } #endregion }
注册代码改为
IUnityContainer container
=
new
UnityContainer() .RegisterType
<
ILogger, TraceLogger
>
() .RegisterType
<
ILogger, MakeFunLogger
>
() .RegisterType
<
IStoplightTimer, RealTimeTimer
>
();
大家也许和我有同样的疑问,这里同时为ILogger注册了两个实例,那么运行时到底是实例哪一个呢?答案是后注册的那个(这个印象中和windsor好像是相反的,呵呵)
2.在配置文件中注册对象的映射 1)添加Configuration相关应用 Microsoft.Practices.Unity.Configuration; System.Configuration2)创建建App.Config
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
configSections
>
<!--
使用编译好的Unity组件 <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
-->
<!--
直接使用Unity源码 (ps:我习惯应用组件不表明Version,因为组件版本是在更新的,如果限死Version有时候很麻烦,当然了,原则上同一组件的接口是不变才行,^_^)
-->
<
section
name
="unity"
type
="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"
/>
</
configSections
>
<
unity
>
<
typeAliases
>
<!--
创建对象别名,不是必须的 其type格式是:对像的全名,程序集名
-->
<
typeAlias
alias
="ILogger"
type
="StopLight.ServiceInterfaces.ILogger, StopLight"
/>
<
typeAlias
alias
="IStoplightTimer"
type
="StopLight.ServiceInterfaces.IStoplightTimer, StopLight"
/>
<
typeAlias
alias
="TraceLogger"
type
="StopLight.ServiceImplementations.TraceLogger, StopLight"
/>
<
typeAlias
alias
="RealTimeTimer"
type
="StopLight.ServiceImplementations.RealTimeTimer, StopLight"
/>
</
typeAliases
>
<
containers
>
<
container
name
="containerOne"
>
<
types
>
<!--
注册映射,这里使用默认的生命周期和实例策略,具体设置可以看文档 ^_^
-->
<
type
type
="ILogger"
mapTo
="TraceLogger"
/>
<
type
type
="IStoplightTimer"
mapTo
="RealTimeTimer"
/>
</
types
>
</
container
>
</
containers
>
</
unity
>
</
configuration
>
3)修改注册代码
//
使用配置文件
IUnityContainer container
=
new
UnityContainer(); UnityConfigurationSection section
=
(UnityConfigurationSection)ConfigurationManager.GetSection(
"
unity
"
); section.Containers[
"
containerOne
"
].Configure(container);
这样就可以使用文件进行配置 ^_^