对话 Spring.NET

阅读数:13959 2008 年 2 月 26 日 02:26

Aleksandar Seovic 是 Solutions for Human Capital 公司的创始人和总经理,该公司专注于企业文档和内容管理领域的软件开发及咨询。他熟悉 Java 和.NET 平台,曾经为全球财富 500 强的公司主持开发了众多项目,这些公司主要来自医疗与金融行业。

Aleks 是 Spring.NET 这个开源的.NET 应用程序框架的领头人之一,并且是这个框架中的 Web、AOP 和 Services(服务)模块的领头开发人员。

Mark Pollack 是 CodeStreet, LLC 的合作伙伴,这是一家为金融行业提供软件开发和咨询的公司。他曾先后担任多种前端办公交易系统(front office trading systems)的架构师和开发人员,这些系统综合使用了.NET 和 Java 技术,并主要运用了基于消息的中间件。在开始他的软件开发生涯之前获得了物理学博士学位。

Mark 从 2003 年以来一直参与了 Spring 框架的开发,并在 2004 年创建了 Spring 的.NET 版本 Spring.NET。

InfoQ:Spring.NET 究竟是什么?为什么.NET 社区需要使用它?

Aleks:Spring.NET 是一个开源的应用程序框架,它可以极大地简化.NET 应用程序开发,甚至于很多功能如果没有它的支持,将非常难以实现。它同时也是 Java 平台下流行的 Spring 框架的“亲弟兄”。但是,如果说 Spring.NET 仅仅是对 Spring 的移植,则有欠公允。事实上,我们在移植 Spring 时,更注重对 Spring 精神的体现,而不是简单的代码移植。

在我早在 2003 年开始使用 Spring 时,我很快就认识到它能够使得我在编写 Java 应用程序时更加快捷,使我的程序代码更加小巧、干净,更具有灵活性,因而易于测试、维护和扩展。在我使用了依赖注入以及 Spring 提供的其它出色功能时,我就情不自禁地希望找到提供类似功能的基于.NET 平台的框架,然而却没有能够找到。大约在同一时间,在 2004 年的早期,Mark 经历了相似的“寻找历程”,从而开始了 Spring.NET 项目的开发。当我听闻这一消息后,就立即加入了这个项目,开始对核心的依赖注入容器以及 AOP 框架进行移植。

Mark:我与 Aleks 首先达成共识的一点就是 Spring.NET 不能盲目地对 Spring 的代码进行移植。Spring 隐含的驱动力是创建了一个框架,它可以降低 J2EE 开发的复杂度,并提供一个简单的、基于 POJO 的编程模型,这一编程模型允许 Spring 应用程序运行在任何 J2EE 容器上。显然,J2EE 与. NET 平台并不相同,它们面临的问题也是不相同的,如果只是试图按照特性对特性的方式将 Spring 移植到.NET,就无异于“买椟还珠”了。而且,. NET 平台自身还存在一些不足,因此我们决定将 Spring.NET 的关注点放在解决这些不足上,以提高.NET 开发人员的生产效率,使得他们能够编写更好、更小以及更干净的代码。开发者可以只关注于业务逻辑,而非基础设施相关的内容。

Aleks:Spring 的其中一些核心功能,例如依赖注入容器和 AOP 框架,是可以通用并且完全独立于平台的,我们对此只是照猫画虎地对代码进行了移植。另一方面,我们认识到 ASP.NET 的实现方式打破了常规,它的强大超过了 Java 中的 servlets 和 JSP,因此我们认为移植 Spring MVC 框架是没有价值的。相反,在 Spring.NET 中,我们选用的 Web 框架只是对 ASP.NET 的封装与扩展。

同样,还有一些组件例如 Spring Remoting,它允许开发者使用一些特定的 Java 技术接受任意的 POJO 对象,并将其作为远程对象输出。类似于这样的情况,我们希望能够将它的理念应用到.NET 中,但是由于在.NET 中对于远程技术的处理方式是不相同的,我们不得不推倒重来。

整体而言,我们的目标不仅仅是要保留 Spring 的功能特性与实现,而且还要保留那些使得 Spring 如此普及的闪光之处,这些特性能够针对.NET 平台存在的问题提供 Spring 风格的解决方案。

InfoQ:你们在谈话中多次提到了依赖注入。可否解释一下它的确切含义,以及为什么.NET 开发人员需要关注它?

Aleks:好的。依赖注入实际上是个非常简单的概念。当你审视一个典型的应用程序时,你会看到对象之间存在许多依赖。表示层对象会依赖于服务层对象,而这些服务层对象又依赖于其它服务对象和数据访问对象等。在一个运行中的应用程序中,会有许多彼此依赖的对象纠缠在一起。

获得一个依赖的最简单方式就是直接调用构造函数创建对象。对象虽然可以被创建,但却存在几个问题:类很难独立测试,如果不修改创建它的代码,就不可能改变它使用的依赖类。这些问题大多数都可以使用某种配置工厂,ServiceLocator 或者 Registry 去创建或查找一个对象来解决。这种方法我们称之为依赖查询(Dependency Lookup),如果实现正确,会收到很好的效果,但是工厂、Service Locator 或 Registry 自身引入的依赖却没有办法解决。它需要做比依赖注入更多的工作。

另一方面,依赖注入意味着一个对象的依赖关系可以通过外部“注入”。不需要为对象查找任何内容——它只是简单地为依赖关系声明了私有字段,允许它们能够被外部提供,提供的方式可以是构造函数的参数或者通过属性的设置器(setter)。这使得对象非常简洁,具有可用性。如果依赖是通过接口声明而非确定的类,同样可以使得相关对象非常易于进行单元测试。

如果你了解了这点,那么对于依赖注入而言就没有什么新颖之处了。无论你是为 IDbCommand 实例设置 Connection 属性,还是设置 Form 实例的 Menu 属性,或者将 Socket 实例作为 NetworkStream 构造函数的参数进行传递,你都可以手动地注入依赖。我在一些旧有技术例如 VB6 或者 COM 中发现了相似的例子。

然而,使得依赖注入在最近几年变得如此普及的原因在于轻量级容器的崛起,这些轻量级容器包括 Java 中的 Spring、Pico 和 HiveMinde,以及.NET 中的 Spring.NET、Castle 和最近微软的 ObjectBuilder。这些容器允许你在应用程序中配置对象配线规则(object-wiring rules)[译注:即把对象连在一起以便它们相互之间能够通信],然后基于这些规则创建应用程序的对象,并将它们连接在一起,从而为开发人员提供自动的依赖注入。不同的容器允许指定的对象配线规则是不相同的,但是最终的目的与结果通常则是相同的。

容器所能够提供不仅限于此。因为他们对管理的所有对象了如指掌,这就使得在运行中的应用程序中管理对象变得轻而易举。我不确定其他容器是否能够做到,但是 Spring 和 Spring.NET 都能够提供钩子(hooks),使得开发者能够在一个对象生命周期的不同状态中执行定制的逻辑,非常的行之有效。

InfoQ:那么 Spring.NET 相对于其他你所提及的其他框架而言,有什么优势呢?

Aleks:好吧,让我们首先比较一下 Spring.NET 与 ObjectBuilder,因为这样的比较相对容易。ObjectBuilder 只是一个轻量级 DI 容器,而 Spring.NET 则拥有其它的功能特性,从而使得它成为一个不错的选择。DI 容器只是这些组件中的一个,虽然它是 Spring.NET 中非常重要的一个。

即使针对纯粹的 DI 功能,Spring.NET 也有着远超 ObjectBuilder 的功能特性,而且它并不具有侵入性。这意味着你的类可以完整地保留与 Spring.NET 的独立性,即使是通过 Spring.NET 对这些类进行配置。反过来, ObjectBuilder 却具有很强的侵入性——它使用 attribute 来指定是哪一个工厂类被用来获取特定的对象,你必须遵循预先定义的准则编写这些工厂类。整体而言,编写 ObjectBuilder 的目的显然是为了支持与 Composite UI Application Block 的配置,而不是通用的、可重用的 DI 容器,甚至微软的 Patterns & Practices 小组也是如此认为的。

Spring.NET 的另一个巨大优势在于,ObjectBuilder 只能用于.NET 2.0 应用程序,而 Spring.NET 则能够用于.NET 1.x 和 2.0 的应用程序。

对比 Spring.NET 与 Castle 相对困难一些。它们都是提供了 DI 容器的框架,也包含了其他组件,例如 Web 框架、数据访问框架等。我对 Castle 的 DI 容器了解不深,无法基于基本的功能点对 Spring.NET 和 Castle 进行点对点的比较,但是我知道 Castle 的 Web 框架以及数据访问框架与我们所实现的略有不同。

究竟是选择 Spring.NET 还是 Castle,我想这需要根据开发人员的技术背景以及特定需求来下判断。就我所知,使用 Ruby On Rails 的开发人员更倾向于使用 Castle,如果开发人员来自 Java 阵营,特别是他们在此之前使用过 Spring,则更倾向于 Spring.NET。我并不确定哪一种框架更适用于.NET 开发人员,但我建议他们最好两者都能够尝试一下,然后选择其中更适合的一个——做出选择远甚于全部放弃。

最后我认为,比较 ObjectBuilder 与 Castle 而言,Spring.NET DI 容器还有一个优势在于,它非常容易在真实的应用程序中进行测试与验证。因为我们继承了 Spring 的 DI 容器实现,因而可以从 Spring 的测试与产品使用中获益。

InfoQ:Spring.NET 适用于哪些场景?

Aleks:Spring.NET 可以应用于许多场景。核心特性如依赖注入(DI)容器、AOP 以及数据访问框架,都可以非常好地应用在任意的.NET 应用程序中。它使得你能够创建更简单、更干净的应用程序。为了尽量消除它所带来的副作用,开发人员还可以免费获得功能强大的配置机制。

如果你正在编写一个 ASP.NET Web 应用程序,你可以考虑将 Spring.NET Web 框架(Spring.Web)加入其中。因为它是 ASP.NET 的一个扩展,所以不会改变 ASP.NET 开发人员的开发方式,同时又为他们提供了一些新的强大功能。例如,它支持 web pages 与 user controls 的依赖注入,这本身就具有充分的理由来选择使用它。然而,最重要的是我们增加了双向数据绑定、进程与状态管理,以及经过改善的本地化支持和增强的数据验证框架。最后,Spring.Web 还为 ASP.NET 1.1 开发人员提供了某些只有在 ASP.NET 2.0 下才能使用的很酷的新特性,例如 Master Pages,它不仅改善了 ASP.NET 1.1 的开发体验,而且还使得从 1.1 到 2.0 的迁移变得更加地容易。

Spring.NET Services Framework(Spring.Services)支持开发者接收一个普通的接口 / 实现对象,然后以远程 SAO 或者 CAO 对象、Web 服务甚至当作一个服务组件输出。然后,通过为输出的远程服务应用方面(aspects),可以实现安全检查、加密、压缩等超级酷炫的事儿。

Spring.Services 的另一个组件是客户端代理生成器,它会提供一个普通的客户端接口以及一个远程终结点(remote endpoint)的 URL,从而为上面提及的任何一种服务类型的远程服务创建动态代理。例如,你可以使用 WebClientFactory 类在运行时动态创建一个 Web 服务代理。通过这种方式创建一个客户端 Web 服务代理,比之于在 VS.NET 中通过使用 Web 引用创建,优势更为明显。首先,你可以提供一个代理需要实现的接口,并通过该接口从客户端应用程序中访问代理。其次,由于接口为你的 Web 服务方法定义了所有的参数与返回类型,因而在你真正需要使用现有的数据类型时,不必处理 VS.NET 生成的伪类型。而这可能是在 VS.NET 中使用 Web 引用所带来的最大困扰之一。

最重要的是,你甚至可以创建一个代理,该代理可以通过我们对 IIOP.NET 的集成,调用 Spring 或者任意 EJB 容器中的 EJB 所管理的远程 Java RMI 对象。目前,这个版本还有一些与序列化相关的功能没有实现,通过这些功能可以实现真正的客户端位置的透明化,我们希望在下一个版本中增加。

Mark:Spring.NET 的数据访问框架(Spring.Data)为‘普通的’ADO.NET 提供了许多颇有价值的修饰。其中一个关键组件就是事务管理的抽象,它允许开发者轻松地在不同的事务策略之间切换,例如普通的旧的 ADO.NET,EnterpriseServices 分布式事务以及新的 System.Transaction 命名空间。所有的事务策略都可以通过嵌入的特性或者非侵入性的 XML 配置来完成。我们对于 ADO.NET 框架的扩展使得 ADO.NET 的操作更简单,并且考虑了连接 / 事务的资源处理——否则在通常情况下,就必须增加开发人员的工作量,即使使用 System.Transactions 命名空间。

Spring.NET 还有几个组件可以脱离于框架单独使用,例如 expression language(表达式语言),它可以很好地消除在应用程序中编写与反射相关代码的需要。

当你决定是否在特定应用程序中使用 Spring.NET 时,切记不要将 Spring.NET 当作一个“整体不可分割”的框架。当你一起使用它们的时候,它们只是一个框架的集合,能够更大程度地完成协作,但也完全可以彼此独立地单独使用。

InfoQ:人们如何在.NET 社区中获得 Spring 的概念?用户的发展情况如何?目前的下载次数以及其他统计数据分别是多少?

Aleks:用户的反馈非常踊跃。在 Java 中使用过 Spring 的开发人员对此雀跃不已,因为在他们转移到.NET 平台进行应用程序开发时,能够使用相同的编程模型,获得相同的益处。从未使用或听说过 Spring 的开发者一旦认识到使用 Spring.NET 可以使得他们的代码更加简单,更加灵活,就会很快被依赖注入以及 Web 框架所吸引。根据论坛所反映的情况来看,依赖注入容器与 Web 框架最为瞩目。

在开发人员试用了 Spring.NET 之后,我们收到了许多积极的反馈与建议,例如,“没有 Spring.NET,我都不会构建应用程序了” 或者 “我希望尽快地掌握它”。像这样的一些评论确实在驱动着我们继续前进,同时验证我们之前所做的工作。

当然,我们每一次都会收到一些问题,例如:“我能够在 Spring.NET 中获得哪些在.NET 2.0/ASP.NET/EntLib/... 中没有的东西?” 对于这些问题,我们都会尽可能坦诚而又全面地回答,并鼓励开发人员自己去尝试 Spring.NET——一旦他们开始使用 Spring.NET,就能一目了然地看到它所带来的好处。

至于商业用户,我们知道华尔街的一些大型公司以及欧美的一些知名石油企业对此颇有兴趣。这这些公司中,有一些本身就是 Spring 的用户,目前又正在寻找经过交叉培训的开发者。由于不同平台都保留了这种编程模型,因而 Spring/Spring.NET 的组合就格外值得关注了。其余的商业用户则是那些希望简化他们开发的.NET 开发团体。我们曾经与一个来自全球知名的石油企业的 Spring.NET 用户有过联系,他告诉我们他们正在使用 Spring.NET 作为企业级开发平台的基础框架。这真的让我们感到非常鼓舞。

Oracle 咨询部门正在他们的项目中使用 Spring.NET 数据访问框架,他们以及一些开展 Spring.NET 培训的咨询公司也从中取得了一定的收获。

在其他领域中,我们还看到软件开发公司对 Spring.NET 给予的极大关注。我们已经与各种软件销售商展开了大量的讨论,这些销售商正在使用 Spring.NET 以支撑他们的产品。Spring.NET 帮助他们缩短了产品上市的时间,减少了他们必须编写与维护的代码量。

Mark:至于统计数据,虽然很容易就可以获得,却很难说得清楚,因此我不打算作这样的尝试。目前,我们在 SourceForge 上每个月有 2000 个下载,但是实际的数字可能更高,因为在过去的 3-4 个月期间,我们通告了最新的每夜构建 [译注:原文为 nightly build,应该代表 daily build 的谐意] 版本可以直接在我们的网站上下载。根据论坛软件的统计,我们拥有800 个注册论坛用户以及超过100 个活跃用户。 FishEye 为我们展示的代码行数在过去的两年半时间内,已经稳步地增长到了超过 50 万行。这还是基于一个前提,那就是我们对于代码行数始终抱有谨慎的态度,只要有机会,我们都会努力去除那些无用的代码。我们应该抱着怀疑的态度来看待这个数字,因为在报告的代码行数中,有 80% 都是单元测试的代码以及文档。 Spring.NET 实际上相当的轻巧:核心程序集包含了核心的 DI 容器,表达式语言,验证框架以及大量的配置与工具类,合计只有 440KB。AOP 框架与 Web 框架的二进制文件则更小,分别只有 96KB 和 88KB。

当然,这些数字相比较 Spring 而言,就未免黯然失色了。自从 Spring 的 2.0 版本在数周之前发布以来,就有超过 50,000 个下载,它也被纽约和伦敦以及其他城市的许多金融部门与银行所使用。但是,我们必须考虑如下现实:Spring 自从 2003 年问世以来,有大量的书籍对其进行了介绍,甚至还有两次专题会议全面对其进行研讨,一次是在美国 ,另一次是在欧洲 。另一方面,大多数Spring.NET 代码仍然处于预发布状态,只有核心的DI 容器和AOP 在2005 年末发布了一个正式版。今天的对话是我们第一次面向广大受众谈论Spring.NET。考虑到这些因素,我们认为能取得这样的成果已经相当不错了。最重要的是,基于目前我们收到的反馈,我们知道自己前进在正确的道路上,随着.NET 开发人员对Spring.NET 的逐渐了解,并认识到它在真实项目中的价值,我们相信会有越来越多的用户接受它。

InfoQ:能否介绍一下在真实的项目开发中,那些基于 Spring.NET 开发成功或失败的用户的看法?

Aleks:对于一个开源项目而言,很难获得这一类的信息。我们根据自身的经验以及论坛的反馈,了解到有大量的成功项目,但是人们通常不愿意宣告自己项目的失败。

毋庸置疑,会有一些失败的案例存在。毕竟,大多数 IT 项目仍然在失败,这让人很沮丧,却是不可争辩的事实。然而,问题是什么导致了项目的失败?从我个人的经验以及我所听到的项目失败经历来看,技术自身通常都不是项目失败的真正原因。即便如此,也完全有可能是某人在不应该使用 Spring.NET 的地方使用了 Spring.NET,从而导致项目失败。但是我们又要看到,如果我用锤子代替灯管去使用,那么究竟是谁的责任:锤子还是我?

Spring.NET 仅仅是工具箱中的一件工具而已。在选择使用的工具时,只要开发者审慎地评估他们的需求,项目就没有理由会因为技术的原因而失败。遗憾的是,开发者尤其是缺乏经验的开发者,总是倾向于使用“一件新鲜玩意儿”去解决所有问题。这种情况只有通过教育培训以及经验积累来解决。

InfoQ:Spring.NET 最近的进展如何?

Mark:我们首先要做的是发布最终的 1.1 版本。该版本包括一个经过改善的 DI 容器与 AOP,以及 Web、Services 和数据访问框架的正式版本。遗憾的是,在最近几个月中,我和 Aleks 都在忙于自己的工作,无法投入我们希望分配给 Spring.NET 的时间。此外,Spring.NET 的两个核心开发人员,Bruno Baia 和 Erich Eichinger,已经修改了我们留下的大多数 bugs,并在诸多方面进行了行之有效的改善。我们可能会在不久的将来发布一个 RC 版本,并在年底发布最终的 1.1 版本。Bruno 与 Erich 一定会非常乐意看到 1.1 版本的“新鲜出炉”。

一旦一切就绪,我们还需要介绍关于使用 Spring.NET 更多的信息。我们会撰写相关的文章,在会议和用户组聚会上进行演讲,不用说,我们还会为 Apress 撰写书籍,这是我们很早以前就欠下的书债,以至于我们都不敢与我们的编辑联系了。

当然,总会有一些很酷的新东西,我们会计划加到未来的版本中……

InfoQ: 未来版本的计划是怎样的?

Aleks:不少工作都很难决定从何处开始……首先,总是需要改进现有的内容,我们会为核心 DI 容器、AOP、Web 框架以及其他将会作为 1.1 版本发布的组成部分添加新的功能特性。至于目前还在我们考虑之中的新特性,我们正在计划为 Windows 应用程序增加一个框架,它可以为 Windows Forms 的开发人员提供类似于 Spring.NET Web 框架为 ASP.NET 开发人员提供的功能。对此,一些工作已将开始,而有的内容则已经完全完成了。例如数据验证框架。目前,它已经可以被用到 Web 框架中,而且也可以无需任何修改应用到 Windows 应用程序中,因为它与表示逻辑完全无关。

Mark:此外,我们还计划完成众多的集成。我们已经拥有如下的集成:集成 NHibernate 实现持久化,集成 Anthem.NET 与 Atlas 实现 AJAX,集成 IIOP.NET 实现与 Java 的互操作,以及为 Web 服务集成 WSE2/WSE3。还有与某些 EntLib 功能模块之间的集成在概念上已经得到了验证,例如 EntLib 中的缓存特性,它支持将 ASP.NET Cache 或者 Caching Application Block 当作方法结果的缓存。然而,还有大量的集成工作需要完成,这些集成工作可以大大地简化基于 Spring.NET 的应用程序对各种工具与技术的使用。

我们正在计划实现与其他用途广泛的工具的集成能力,例如:实现持久化的 Wilson ORM 与 iBatis.NET,针对消息传输的 TIBCO、MSMQ 以及 MQSeries,还有与所有 EntLib 功能块的完整的、达到产品质量的集成……在互操作方面,还有许多令人激动的特性会被实现,我们正努力消除平台的边界性,并使得 Spring.NET 与 Spring 管理的 Java 远程服务之间进行相互调用成为可能。我们希望这种交互尽可能地像在一个单独平台上进行交互那样简单。我们还将提供对 BizTalk 的集成,对 SharePoint 的支持等。一言以蔽之,我们将根据用户的需求来决定我们需要集成哪些产品和工具,并排定实现他们的优先级。毋庸置疑,这其中的一些集成实际上就是来自于用户本身。

Aleks:此外,随着微软推出的众多令人激动的技术与产品,我们也会尽快实现改进与集成。当我正在关注 FishEye 的统计结果时,我想 Bruno[译注:Spring.NET 的一位项目成员] 已经将 WPF 的 glue code[译注:glue code 是为了连接一个可以重用,并且已经存在的应用程序而编写的代码。例如有两个程序包 A 和 B,A 和 B 之间没有任何依赖关系,如果希望在程序中让 A 和 B 之间进行协作,就需要编写 glue code。glue 是胶水的意思,这里取用了粘贴剂的隐喻] 提交到了 sandbox 中。同样还有 Windows Communication Foundation,它可以使得我们的远程能力更加强大;Workflow Foundation 则可以为我们的 Web 框架在进程管理方面提供改进。我们能够持续跟进,但关键是有太多令人激动的新技术与产品如“雨后春笋”一般诞生,我相信接下来的几年将是整个 Spring.NET 团队充满艰辛与乐趣的时期。希望在这段时间内,我们的用户能够多一点乐趣,多一些成果,少一些艰辛与困难:-)

InfoQ:如果我对 Spring.NET 很有兴趣,那么我应该从哪里开始?

Mark:最佳起点当然是我们的网站 www.springframework.net ,在那里你能够找到下载区。在接下来的几周时间内,我们力图发布 3 个预览版本以及 1 个 RC 版本,但是在这期间,你最好是下载我们最近的每夜构建版本。在下载包中包含了许多范例,我们鼓励用户仔细地阅读它们,以明确项目使用了 Spring.NET 特性,会有何不同。

你还可以找到文档区的链接,以及用户论坛,这些都是寻求帮助的最佳位置。我们希望很快能够在那里见到你:-)

查看英文原文: Spring.NET - QnA

评论

发布