First we try, then we trust

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  183 随笔 :: 111 文章 :: 2960 评论 :: 298 Trackbacks

本系列的全部源代码及二进制文件可以从这里下载: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的改造,并比较两者之间的区别。

(待续)

posted on 2005-09-10 20:06 吕震宇 阅读(4366) 评论(8)  编辑 收藏 所属分类: 面向对象技术

评论

感觉在开发程序插件。
  回复  引用    

#2楼  2006-08-10 22:03 flyingchen [未注册用户]
能具体介绍下xml的具体含义吗?
  回复  引用    

#3楼  2006-08-28 15:12 lxwlxw [未注册用户]
Rod Johnson《J2EE without EJB》中文 版已經出版了
  回复  引用    

#4楼  2006-12-01 14:53 小C      
我更改了一个文件名 SayHello.dll 为SayHello1.dll Spring将出错,而现有配置中根本找不到配置文件名的地方。

其实我想实现的功能就是主程序MainApp.exe,可以载入很多的插件,像eclipse那样,插件都放在plugins目录下,mainApp.exe 每次启动会扫描plugins下的dll,并载入。然后我在MainApp.exe可以通过配置文件决定初始化那些对象,或者配置菜单然后show出哪些插件,但在MainApp项目中并没有引用这些对象。这个用.net的反射可以做,不过我相信spring.net或castle应该可以完成这些工作。不过我没有找到相应配置方法。请教方法。

希望我描述的还算清楚,谢谢

  回复  引用  查看    

<object id="mySayHello" type="IocInCSharp.SayHello, SayHello">
其中的type中的 逗号后面SayHello就是程序集名。
一个项目的程序集名可以在项目属性中设置,设置好后就是生成的DLL的名字。
只要type中的程序集名与你目录中的DLL名一致就OK了。

你只改DLL的名字,不改生成项目的程序集名肯定不行的。

不知道说明白没有。
  回复  引用    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-09-12 08:44 编辑过


相关链接: