本系列的全部源代码及二进制文件可以从这里下载:IocInCSharp.rar

你真的了解Ioc与AOP吗?(1)

你真的了解Ioc与AOP吗?(2)

你真的了解Ioc与AOP吗?(3)

你真的了解Ioc与AOP吗?(4)

你真的了解Ioc与AOP吗?(5)


本部分示例代码请参考"src/Step3"目录

四、使用Spring.net实现依赖注入

Spring在Java界可是响当当的名字,现在也有.net平台下的Spring框架了,那就是Spring.net。用户可以从http://www.springframework.net/下载到Spring.net的最新版本。本例子中使用的版本为“Spring Interim Build August 15, 2005 ”,并对Spring.Services组件中的Remoting部分做了微小调整,删除了代码中用于输出的部分命令。

Spring.net为我们提供了一种基于配置文件的注入方式,目前Spring.net允许将值注入到属性,也允许将一个工厂绑定到属性,工厂的产品将注入属性;除此之外,Spring.net还允许将一个方法的返回结果绑定到属性;它还可以在绑定之前强制进行初始化。另外Spring.net还专门针对.net提供了Remoting以及Windows Service的“注入”方式。Spring.AOP允许完成横切(不过目前是调用的是AopAlliance的代码)。

尽管我对基于配置文件的注入方式仍然有些偏见(我认为它很难Debug、难于理解、没有编译时错误校验、编写效率比较低。另外它还存在安全隐患 ,恶意用户可以借助修改配置文件将恶意代码注入系统。因此,Spring.net在Web开发中应当更具优势),但这并不能掩盖Spring.net的光芒(据说Castle比Spring.net要好,但目前我还没有尝试过使用Castle)。使用Spring.net,我们只需修改两三行代码,并提供相应配置文件,就可以轻松实现Ioc。应用Spring.net后,我们的系统依赖关系如下图所示:


 

从图中可以看出,MainApp、SayHello、HelloGenerator之间并不存在任何依赖关系,它们都依赖于抽象出来的接口文件。除此之外,MainApp还依赖于Spring.net,这使得MainApp可以借助Spring.net实现组件动态创建和组装。

对于原有代码,我们几乎不用作任何调整,唯一需要修改的就是MainApp中的调用方法,代码如下:

using System;
using System.Configuration;
using Spring.Context;
namespace IocInCSharp
{
   public class MainApp
   {
      public static void Main()
      {
         try
         {
            IApplicationContext ctx = ConfigurationSettings.GetConfig("spring/context") as IApplicationContext;
            ISayHello sayHello = (ISayHello)ctx.GetObject("mySayHello");
            sayHello.SayHelloTo("zhenyulu");
         }
         catch (Exception e)
         {
            Console.WriteLine(e);
         }
      }
   }
}

首先我们要添加对Spring.Context命名空间的引用,然后解析配置文件的"spring/context"结点,得到一IApplicationContext对象(就好比在上一个例子中我们得到的ConfigInfo对象一样),剩下的事情就是向该Context索要相关的对象了(ISayHello)ctx.GetObject("mySayHello"),其中"mySayHello"由配置文件指定生成方式和注入方式。

配置文件的内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <sectionGroup name="spring">
         <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
         <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
      </sectionGroup>
   </configSections>
   <spring>
      <context>
         <resource uri="config://spring/objects" />
      </context>
      <objects xmlns="http://www.springframework.net">
         <object id="mySayHello" type="IocInCSharp.SayHello, SayHello">
            <property name="HelloGenerator">
               <ref object="myCnHelloGenerator" />
            </property>
         </object>
         <object id="myEnHelloGenerator" type="IocInCSharp.EnHelloGenerator, HelloGenerator" />
         <object id="myCnHelloGenerator" type="IocInCSharp.CnHelloGenerator, HelloGenerator" />
      </objects>
   </spring>
</configuration>

注意观察<object id="mySayHello".....>结点,就是由这里定义对象间相互依赖关系的。其中的<property name="HelloGenerator">结点定义了对什么属性执行注入,以及注入的内容是什么(<ref object="myCnHelloGenerator" />)。大家可以尝试将<ref object="myCnHelloGenerator" />改为<ref object="myEnHelloGenerator" />,看一看程序执行结果有什么变化来体会Spring.net的Ioc功能。

如果读者读到这里仍然觉得Ioc没有什么的话,那让我们再来看一个更为复杂的例子。在当前例子中,MainApp通过依赖注入调用了HelloGenerator的功能,但所有的调用都发生在本地。当前程序是一个地地道道的本地应用程序。现在如果要求在不更改一行代码的情况下,将HelloGenerator.dll放到另外一台计算机上,MainApp通过远程调用(Remoting)来访问HelloGenerator的功能。这似乎就有一定的难度了。

这么作并不是没有任何依据,其实Ioc除了可以实现依赖注入外,我们还应当看到它可以将我们从复杂的物理架构中解脱出来,专心于业务代码的开发。系统开发中关键是逻辑分层。在一个系统不需要Remoting时,开发的系统就是本地应用程序;当需要Remoting时,不用修改任何代码就可以将系统移植为分布式系统。Ioc使这一切成为可能。Rod Johnson在他的《J2EE without EJB》一书中有着详细的论述,很值得一读。据说该书的中文译本今年九月份出版(呵呵,就是这个月,不过我还没有看到市面上有卖的)。

为了能够更深入的分析在“Remoting”改造过程中我们可能遇到的麻烦,在后续两部分内容中,我们将分别介绍不使用Ioc的Remoting改造以及使用Ioc的改造,并比较两者之间的区别。

(待续)


本文转载:CSDN博客