企业开发框架NHibernate和Spring.Net简介

在开始介绍NHibernate和Spirng.Net以前,有必要先介绍一下相对应的两个Java开源框架Hibernate和Spring。它们是在Java的Web应用开发中已经很成熟的框架,而前者则是两个还不成熟的.Net中的开源框架,它们在SourceForge开源社区中正在获得不断的补充和完善,其最终目标就是要在.NET环境下实现Hibernate和Spring的所有  特性。
Spring是一个解决了许多在J2EE开发中常见问题的强大框架,它提供了管理业务对象的一致方法而且鼓励注入对接口编程而不是对类编程的良好习惯。Spring提供了惟一的数据访问抽象,包括简单和有效率的JDBC框架,极大改进了效率而且减小了可能的错误。Spring的数据访问架构还集成了Hibernate和其余O/R mapping解决方案。Spring还提供了惟一的事务管理抽象,它为各类底层事务管理技术,例如JTA或者JDBC事务提供一个一致的编程模型。Spring提供了一个用标准Java语言编写的AOP框架,它给POJO提供了声明式的事务管理和其余企业事务。这个框架足够强大,使得应用程序可以抛开EJB的复杂性,同时享受着和传统EJB相关的关键服务。Spring还提供了能够和IoC容器集成的强大而灵活的MVC Web框架。
Hibernate是一个开放源代码的对象关系映射(Object-Relation Mapping,ORM)框架,它对JDBC进行了很是轻量级的对象封装,使得Java程序员能够为所欲为地使用对象编程思惟来操纵数据库。Hibernate能够应用在任何使用JDBC的场合,既能够在Java的客户端程序使用,也能够在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate能够在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。鉴于Hibernate在Java社区巨大的影响力,它其实已经成为Java社区的持久层技术事实上的标准。
基于.NET的开发框架NHibernate和Spring.Net分别来源于上述提到的两个Java框架,框架结构和实现功能都基本一致,只不过应用环境从Java转到了.NET。到目前为止NHibernate和Spring.NET仍然处于完善阶段,不是特别成熟稳定,可是具备Hibernate和Spring的强大背景,使得它们有着很光明的将来。事实上,如今NHibernate和Spring.NET正在被愈来愈多的开发人员所熟知,而且有些开发人员已经开始尝试在本身的项目中使用这两个框架。
1.5.1  企业开发框架的优点
在当今的企业环境中,开发企业应用程序是一个至关繁琐、浪费时间的过程,为了让这个过程变得相对简单且高效,一些开源的、轻量级的框架正在被普遍的使用,好比Java下的Structs、Spring、Hibernate、iBATIS以及.NET下的Spring.Net和NHibernate等。
它们的普遍使用下降了系统开发的复杂度,弱化了系统各模块间的耦合程度,缩短了开发周期,加强了系统的可维护性和可扩展性。“站在巨人的肩膀上”是牛顿的一句名言,它已经成为google学术搜索引擎的座右铭,一样也为笔者所推崇。笔者对.Net软件开发平台的设想以下,采用开源的ORM框架作数据持久层,ASP.NET没有合适的Web层框架,采用Asp.Net的Code-behind方式编写代码,数据持久层同Web表现层之间的链接采用IoC容器。
衡量了多种框架之后,最终笔者推荐采用的技术架构就是NHibernate+Spring.Net+ASP.NET,下面对NHibernate和Spring.net分别进行比较详细的介绍。
1.5.2  NHibernate介绍
在今日的企业环境中,把面向对象的软件和关系数据库一块儿使用多是至关麻烦和浪费时间的。NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。
NHibernate不只仅管理.NET类到数据库表的映射(包括.NET 数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,能够大幅度减小开发时人工使用SQL和ADO.NET处理数据的时间。
NHibernate的目标主要是用于与数据持久化相关的编程任务,可以使开发人员从原来枯燥的SQL语句的编写中解放出来,解放出来的精力可让开发人员投入到业务逻辑的实现上。对于以数据为中心的程序,开发人员每每是在数据库中使用存储过程来实现商业逻辑,这种状况下NHibernate可能不是最好的解决方案,但对于那些基于.NET,而且可以实现OO业务模型和商业逻辑的中间层应用,NHibernate是最有用的。NHibernate能够帮助用户消除或者包装那些针对特定厂商的SQL代码,而且帮用户把结果集从表格式的表示形式转换成一系列的对象。
1.NHibernate体系结构
NHibernate体系结构如图1-51所示。它体现了NHibernate如何使用数据库和配置文件数据来为应用程序提供持久化服务(和持久化的对象)。
在NHibernate全面解决体系中,NHibernate运行时体系结构的细节如图1-52所示。
      
     图1-51  NHibernate体系结构                      图1-52  NHibernate详细体系结构
*    SessionFactory(NHibernate.IsessionFactory):它是Session的工厂,是ConnectionProvider的客户。能够持有一个可选的(第二级)数据缓存,能够在进程级别或集群级别保存的能够在事物中重用的数据。
*    会话(NHibernate.ISession):单线程,生命期较短的对象,表明应用程序和持久化层之间的一次对话。封装了一个ADO.NET链接,也是Transaction的工厂。保存有必需的(第一级)持久化对象的缓存,用于遍历对象图,或者经过标识符查找对象。
*    持久化对象(Persistent)及其集合(Collections):生命期较短的单线程的对象,包含了持久化状态和商业功能。这些多是普通的对象,惟一特别的是如今从属于且仅从属于一个Session。一旦Session被关闭,它们都将从Session中取消联系,能够在任何程序层自由使用(好比,直接做为传送到表现层的DTO,数据传输对象)。
*    临时对象(Transient Object)及其集合(Collection):目前没有从属于一个Session的持久化类的实例。这些多是刚刚被程序实例化,尚未来得及被持久化,或者是被一个已经关闭的Session实例化。
*    事务Transaction (NHibernate.ITransaction):(可选)单线程,生命期较短的对象,应用程序用其来表示一批工做的原子操做,它是底层的ADO.NET事务的抽象。一个Session在某些状况下可能跨越多个Transaction事务。
*    ConnectionProvider(NHibernate.Connection.ConnectionProvider):(可选)ADO.NET链接的工厂。从底层的IDbConnection抽象而来。对应用程序不可见,但能够被开发者扩展/实现。
*    TransactionFactory(net.sf.hibernate.TransactionFactory):(可选)事务实例的工厂。对应用程序不可见,但能够被开发者扩展/实现。
2.持久化类
持久化类是应用程序用来解决商业问题的类(好比,在电子交易程序中的Customer和Order)。持久化类是暂时存在的,实例会被持久性保存于数据库中。
若是这些类符合简单的规则,NHibernate可以工做得最好,这些规则就是Plain Old CLR Object(POCO,简单传统CLR对象)编程模型。
POCO简单示例(用一个类描述一只猫)以下:
#001    public class Cat
#002    {
#003       private long _id;                  // 标识符
#004       private string _name;             // 名字
#005       private DateTime _birthdate;        // 出生日期
#006       private Cat _mate;                // 猫的配对
#007       private Set _kittens;                 // 猫仔
#008       private Color _color;               // 颜色
#009       private char _sex;              // 性别
#010       private float _weight;             // 体重
#011           public long Id              // 标识符属性
#012      {  get { return _id; }
#013              set { _id = value; }
#014       public string Name              // 名字属性
#015           {  get { return _name; }
#016          set { _name = value; }}
#017       public DateTime Birthdate          // 出生日期属性
#018           {  get { return _birthdate; }
#019              set { _birthdate = value; }}
#020       public Cat Mate                 // 猫的配对属性
#021           {  get { return _mate; }
#022         set { _mate = value; }}
#023       public Set Kittens              // 猫仔属性
#024           {  get { return _kittens; }
#025              set { _kittens = value; }}
#026       public Color Color              // 颜色属性
#027           {  get { return _color; }
#028              set { _color = value; }}
#029       public char Sex                 // 性别属性
#030           {  get { return _sex; }
#031              set { _sex = value; }}
#032       public float Weight             // 体重属性
#033           {  get { return _weight; }
#034              set { _weight = value; }}
#035    }
有4条主要的规则以下。
*    为持久化字段声明访问器(getters和setters)。
*    Cat为它的全部可持久化字段声明了getters和setters访问器。用访问器来替代直接访问字段是个好习惯。也能够经过字段(field)来使用NHibernate。属性不必定须要声明为public的。NHibernate能够对default、protected、internal或private的属性执行持久化。
*    实现一个默认的构造方法(constructor):Cat有一个显式的无参数默认构造方法。全部的持久化类都必须具备一个默认的构造方法(能够不是public的),这样NHibernate就可使用Constructor.Invoke()来实例化它们。
*    提供一个标识属性(identifier property)(可选)。
*    建议使用不是sealed的类(可选)。
3.NHibernate映射
对象和关系数据库之间的映射是用一个XML文档(XML document)来定义的。这个映射文档被设计为易读的,而且能够手工修改。映射语言是以.NET为中心的,意味着映射是按照持久化类的定义来建立的,而非表的定义。在Hibernate中XML映射文档能够手动定义,也有一些工具来辅助生成,包括Xdoclet、Middlegen和AndroMDA,可是在NHibernate文档中并无上述的辅助工具,不过能够采用MyGeneration这样的代码生成工具来生成XML配置文档。下面是一个映射的例子:
#001  <?xml version="1.0" ?>
#002  <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" namespace="Eg" assembly="Eg">
#003  <class name="Cat" table="CATS" discriminator-value="C">
#004       <id name="Id" column="uid" type="Int64">
#005          <generator class="hilo"/>
#006       </id>
#007       <discriminator column="subclass" type="Char"/>
#008       <property name="Name" type="Char"/>
#009       <property name="Color" not-null="false"/>
#010       <property name="Sex" not-null="false" update="false"/>
#011       <property name="Weight"/>
#012       <many-to-one name="Mate" column="mate_id"/>
#013       <set name="Kittens">
#014          <key column="mother_id"/>
#015          <one-to-many class="Cat"/>
#016       </set>
#017       <subclass name="DomesticCat" discriminator-value="D">
#018          <property name="Name" type="String"/>
#019       </subclass>
#020  </class>
#021  </hibernate-mapping>
全部的XML映射都须要使用nhibernate-mapping-2.0 schema。目前的schema能够在NHibernate的资源路径或者是NHibernate.dll的嵌入资源(Embedded Resource)中找到。NHibernate老是会优先使用嵌入在资源中的schema文件。在使用VisualStudio.NET时,用户应该将hibernate-mapping拷贝到C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\ Packages\schemas\xml路径中,以得到智能感知功能。
#002行:hibernate-mapping这个元素包括4个可选的属性。schema属性,指明了这个映射所引用的表所在的schema名称。倘若指定了这个属性,表名会加上所指定的schema的名字扩展为全限定名。倘若没有指定,表名就不会使用全限定名。default-cascade指定了未明确注明cascade属性的属性和集合类会采起什么样的默认级联风格。auto-import属性默认在查询语言中可使用非全限定名的类名。default-access告诉用户怎么访问属性值。倘若有两个持久化类,它们的非全限定名是同样的,应该设置auto-import= "false"。倘若把一个“import”过的名字同时对应两个类,NHibernate会抛出一个异常。
#003行:使用class元素来定义一个持久化类。name是持久化类(或者接口)的全限定名。table是对应的数据库表名。discriminator-value(可选 - 默认和类名同样)是一个用于区分不一样的子类的值,在有多态行为时使用。
#004行:使用id来标识主键字段,由于被映射的类必须声明对应数据库表主键字段。大多数类有一个属性,为每个实例包含惟一的标识。<id> 元素定义了该属性到数据库表主键字段的映射。
#005行:必须声明的 <generator> 子元素是一个.NET类的名字,用来为该持久化类的实例生成惟一的标识。其中hilo(高低位)使用一个高/低位算法来高效地生成Int6四、Int32 或者Int16类型的标识符。给定一个表和字段(默认分别是hibernate_unique_key 和next)做为高位值的来源。高/低位算法生成的标识符只在特定的数据库中是惟一的。
#007行:在“一棵对象继承树对应一个表”的策略中,<discriminator>元素是必需的,它声明了表的识别器字段。识别器字段包含标志值,用于告知持久化层应该为某个特定的行建立哪个子类的实例。只能使用以下受到限制的类型:String,Char,Int32,Byte,Int16,Boolean,YesNo,TrueFalse。
#008-011行:<property>元素为类声明了一个持久化的属性。name是属性的名字,type(可选)是一个NHibernate类型的名字,not-null(可选)代表这个属性是否为空,update(可选-默认为true)代表在用于UPDATE的SQL语句中是否包含这个字段。
#012行:经过many-to-one元素,能够定义一种常见的与另外一个持久化类的关联。这种关系模型是多对一关联(其实是一个对象引用)。
#013-016行:<set>为集合类标识,其中discriminator-value(可选 - 默认为类名)用于区分每一个独立的子类的值。
#017行:子类(subclass),多态持久化须要为父类的每一个子类都进行声明。对于上面建议的“每一棵类继承树对应一个表”的策略来讲,就须要使用<subclass>声明。
4.NHibernate应用实例
上面已经编写好了Cat类和相应的映射文件,为了正确调用Nhibernate,必须对web.config配置文件进行配置。具体配置代码以下:
#001  <xml version="1.0" encoding="utf-8" ?>
#002  <configuration>
#003       <configSections>
#004           <section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System Version=2.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
#005       </configSections>
#006       <nhibernate>
#007           <add
#008                key="hibernate.connection.provider"
                     value="NHibernate.Connection.DriverConnectionProvider" />
#009           <add
#010                key="hibernate.connection.driver_class"
                    value="NHibernate.Driver.SqlClientDriver" />
#011           <add
#012                key="hibernate.connection.connection_string"
                    value="server=localhost;uid=sa;pwd=123;database=Sample" />
#013           <add
#014                key="hibernate.connection.isolation" value="ReadCommitted" />
#015           <add
#016                key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
#017       </nhibernate>
#018  </configuration>
#012行:hibernate.connection.connection_string的value为链接服务器ConnectoinString。其余的都是Nhibernate运行所必需的配置信息。
配置完web.config文件,在测试工程中引用NHibernate.dll和Eg,具体代码以下。
#001    using System;
#002    using System.Collections.Generic;
#003    using System.Text;
#004   using NHibernate;
#005    using NHibernate.Cfg;
#006    using POJOLibrary;
#007    namespace Test
#008    {
#009        class Program
#010        {
#011            static void Main(string[] args)
#012            { Configuration c = new Configuration();
#013                c.AddAssembly("Eg");
#014                ISessionFactory factory = c.BuildSessionFactory();
#015               ISession s = factory.OpenSession();
#016               ITransaction t = s.BeginTransaction();
#017                Cat cat = new Cat();
#018                cat.Name = “Bolo”;
#019                 cat.Color = “Black”;
#020                 cat.Sex = “Male” ;
#021                 cat.Weight = “12” ;
#022                s.Save(cat);
#023                t.Commit();}
#024        }
#025    }
NHibernate是经过Isession的实现类来提供功能的,上面代码经过Itransaction打开一个事务t=s.BeginTransaction(),最后经过调用t.Commit()提交事务,将数据写入数据库中。
经过上述NHibernate的一个简单的应用实例能够看到,整个应用程序中没有写任何一句SQL语句。
虽然NHibernate目前不是很是的成熟,尚未达到实用化的水平,它常常在负荷有些大的时候崩溃,可是它脱胎于在Java社区有着巨大影响力的Hibernate,并且NHibernate在实际应用方面确实体现出了它的优点,基于上述缘由NHibernate必定会被愈来愈多的开发人员所接受,并且必定会被标准化。到目前为止,NHibernate的最新版本为1.1,官方站点[url]http://nhibernate.sourceforge.net/[/url]上目前的版本是beta 0.7.0.0。
1.5.3  Spring.Net介绍
Spring.Net是一个关注于.NET企业应用开发的应用程序框架,它可以提供很是丰富的功能,例如依赖注入(Dependency Injection),面向方面编程(Aspect Oriented Programming),数据访问抽象以及ASP.NET集成等。Spring.NET脱胎于Java的Spring框架,其1.0版包括了一个功能完整的反转控制容器和AOP函数库,在后续的版本中将包含对ASP.NET、Remoting和数据访问的支持。Spring.Net的框架如图1-53所示。
图1-53  Spring.Net的框架图
1.控制反转
控制反转 (IoC, Inversion of Control )意味着将设计好的 交给系统去控制,而不是在本身的类内部控制。
IoC是近年来兴起的一种思想,主要是协调各 组件 间相互的依赖关系,同时大大提升了组件的可移植性,组件的重用机会也变得更多。在传统的实现中,由 程序 内部代码来控制程序之间的关系。咱们常用new关键字来实现两组键间关系的组合,这种实现地方式会形成组件之间耦合(一个好的设计,不但要实现代码重用,还要将组件间关系解耦)。IoC很好地解决了该问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。
分离关注(Separation of Concerns:SOC)是产生IoC模式和 AOP 的最原始动力,经过功能分解可获得关注点,这些关注能够是组件、方面或服务。
GOF设计模式 中,咱们已经习惯一种思惟编程方式——接口驱动。接口驱动有不少好处,能够提供灵活的子类实现,增长代码稳定和健壮性等,可是接口必定是须要实现的,即以下语句必定要执行。
AInterface a = new AInterfaceImp();
AInterfaceImp是接口AInterface的子类,Ioc模式能够根据须要延缓接口的实现,有个比喻:接口如同空的模型套,在必要时向模型套注射石膏,成为一个模型实体。能够人为控制接口的实现完成“注射”。
IoC的实现方式有如下几种:
*    基于接口的(Interface-based IoC,Type-1)。
*    基于设值的(Setter-based IoC,Type-2)。
*    基于构造的(Construtor-based IoC,Type-3)。
下面经过简单的例子分别介绍上述几种实现方式。
(1)Type-1。基于接口的设计方法一般是利用接口将调用者与实现者分离。
#001  public class Sport {
#002  private InterfaceBall ball; //InterfaceBall是定义的接口
#003  public void init() {
#004  //Basketball实现了InterfaceBall接口
#005  ball = (InterfaceBall) Class.forName("Basketball").newInstance();}
#006  }
Sport类在编译期依赖于InterfaceBall的实现,为了将调用者与实现者分离,能够动态生成Basketball类并将其强制类型转换为InterfaceBall。
(2)Type-2。基于设值的设计方法是经过在类中暴露setter方法来实现依赖关系。
#001  public class Sport {
#002  private InterfaceBall _ball;
#003  public InterfaceBal1 ball
#004  {
#005      set{ _ball = value ;} }
#006  }
Spring.NET就是实现了该类型的轻量级容器。
(3)Type-3。经过构造方法完成依赖关系。
#001  public class Sport {
#002  private InterfaceBall ball;
#003  public Sport(InterfaceBall arg) {
#004  ball = arg; }
#005  }
因为Type-3在构造期就造成了对象的依赖关系,因此对对象的重用变得困难。有些框架须要组件提供一个默认的构造方法,此时就显现出Type-3的局限性。一般全部的参数都是经过构造方法注入的,当对象间的依赖关系较多时,构造方法就显得比较复杂,不利于单元测试。PicoContainer就是实现了Type-3依赖注入模式的轻量级容器。
2.Spring.NET库
Spring.NET库有6个基本组成部分,基本上涵盖了Spring.NET框架的全部功能结构。
*    Spring.Core库是Spring.NET框架最基础的部分,它提供了依赖注入的功能。Spring.NET中大部分的函数库都依赖于这个核心库提供的功能,或者是对核心库的扩展。IObjectFactory是核心容器接口,负责管理容器内的注入对象,而IApplicationContext则是IObjectFactory的继承,它扩展了一些功能。
*    Spring.Aop库为商业逻辑对象提供了面向方面编程的支持,它为建立企业应用和为商业对象提供服务打下了基础,是Spring核心库中IoC容器的补充。
*    Spring.Web库为ASP.NET增长了不少功能,例如ASP.NET页面的依赖注入,数据双向绑定,为ASP.NET提供母版页功能,加强了本地化支持。全部的这些都是对ASP.NET很好的扩展。
*    Spring.Services库能够将任何一个“普通”对象(“普通”是指该对象不是继承自特殊服务的基类)暴露成为一个企业应用(COM+)或者远程对象。由于对依赖注入和原数据属性重载的支持,.NET 中的Web服务会得到更好的配置上的灵活性。一样,该库也提供了对Windows服务的支持。
*    Spring.Data库为.NET提供了一个数据访问层的抽象,它可以用于从ADO.NET到多种ORM Provider的数据访问提供者。它同时包含了一个ADO.NET抽象层,简化了对ADO.NET的编码和事务管理。
*    Spring.ORM库提供了一个用于常见的对象—关系映射库的综合层,它提供了诸如对事务管理的支持等功能。
3.面向方面编程(AOP)
面向方面编程是对面向对象编程(OOP)的补充,是另一种思考编程框架的方法。面向对象是将应用分解成具备层次结构的对象;而面向方面编程则是把程序分解成方面或者关注点,使诸如事务管理等方面的模块化成为可能。Spring.NET中很关键的一个组件就是AOP框架。可以帮助Spring.NET的 IoC容器为企业应用提供一个很是强大的中间件解决方案。
AOP用于Spring.NET能够完成下列功能。
*    提供公开的企业服务,尤为是做为COM+公开服务的替代者。这些服务中最重要的服务是公开的事务管理,这是Spring.NET事务抽象的基础。
*    容许用户实现定制的方面,经过面向方面编程来补充面向对象编程的不足。
用户不但能够把Spring.NET AOP看做是可以不经过COM+就能够提供公开事务管理的技术,并且还能够充分发挥Spring.NET AOP框架的功能区实现定制方面。
经过上面的介绍读者可能对AOP已经有了一个大体的了解,下面介绍几个关于AOP的概念。
*    方面(Aspect):这个是一个让读者感受比较模糊的概念,它和一般意义上的方面不彻底同样,它是对关注点的模块化,这可能会横切多个对象。事务管理是一个很是好的横切关注点企业应用的例子。在Spring.NET中,方面做为建议者或者监听器的形式实现。
*    链接点(Jointpoint):程序运行期间的一些点,例如方法调用或者特殊的异常被抛出。
*    建议(Advice):AOP框架在一个特殊链接点上采起的动做。这些不一样类型的建议包括“around”、“before”和“throws” 等建议。不少AOP框架,包括Spring.NET,都把一个建议模拟成一个监听器,同时维护一个“around”链接点的监听器链。
*    切点(Pointcut):一组链接点,用于指定建议应该激活的时间。一个AOP框架必须可以容许开发人员指定切点,例如,使用正则表达式。
*    介绍(Introduction):添加方法或域到建议类。Spring.NET容许介绍一个新的接口到任何一个建议对象中。例如,为了简化对对象状态变化的跟踪,可使用建议为任何对象实现一个IAuditable接口。
*    目标对象:包含链接点的对象。
*    AOP代理:由AOP框架建立的对象,包括建议。在Spring.NET中,一个AOP代理是一个在运行期使用IL代码生成的动态代理。
*    Weaving:装配对象建立一个被建议对象。装配工做发生在编译期(例如使用Gripper-Loom .NET编译器),也能发生在运行期。Spring.NET在运行期执行装配动做。
4.Spring.NET应用实例
下面以经典的Movie Finder做为Spring.NET应用实例来说解IoC容器的使用方法。实例的C#代码能够在Spring.NET发布版的examples/Spring/Spring.Examples.MovieFinder目录中找到。
(1)Movie Finder。MovieFinder例子的起始类是MovieApp类,这是具备单一应用程序入口点的普通.NET类。代码以下所示:
#001  using System;
#002  namespace Spring.Examples.MovieFinder
#003  {
#004      public class MovieApp
#005      {
#006           public static void Main ()
#007           {
#008           }
#009      }
#010  }
如今想作的是得到一个对MovieFinder类实例的引用。这是Spring.NET例子,因此要从Spring.NET的IoC容器类IApplicationContext得到这个引用。应用程序配置文件中的IApplicationContext配置信息以下:
#001  <?xml version="1.0" encoding="utf-8" ?>
#002  <configuration>
#003  <configSections>
#004  <sectionGroup name="spring">
#005  <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
#006  <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
#007  </sectionGroup>
#008  </configSections>
#009  <spring>
#010  <context>
#011  <resource uri="config://spring/objects"/>
#012  </context>
#013  <objects>
#014  <description>An example that demonstrates simple IoC features.</description>
#015  </objects>
#016  </spring>
#017  </configuration>
将在应用程序示例中用到的对象配置成嵌套在<objects/>元素中的<object/>元素。
(2)得到IApplicationContext应用。代码以下所示:
#001  using System;
#002  using System.Configuration;
#003  using Spring.Context;
#004  ...
#005  public static void Main ()
#006  { IApplicationContext ctx = ContextRegistry.GetContext();}
#007  ...
如上所述,using System.Configuratoin和using Spring.Context两条using语句被加到了MovieApp类文件中。其中,System.Configuration命名空间可让应用程序存取保存在配置文件中的Spring.NET的IoC容器的定义;Spring.Context命名空间可让应用程序存取IApplicationContext类,这个类是应用程序存取Spring.NET所提供的功能的主要方法。
方法main得到一个IApplicationContext的实现,它的配置信息已经被写在应用程序配置文件内名为<objects/>的节中。
(3)第一个对象的定义。到目前为止,在应用程序配置文件中尚未对象定义,因此下面定义一个对象。MovieLister实例的XML定义以下所示。
#001  ...
#002  <objects>
#003    <object name="MyMovieLister"
#004           type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
#005    </object>
#006  </object>
#007  ...
#003行:MyMovieLister是该对象的惟一标识符,使用这个标识符,这个对象的实例就可以被以下所示的代码中的IApplicationContext引用所获取。
#001  ...
#002  public static void Main ()
#003    { IApplicationContext ctx = ContextRegistry.GetContext();
#004      MovieLister lister = (MovieLister) ctx.GetObject ("MyMovieLister");}
#005  ...
lister实例仍然没有与IMovieFinder接口相应的实现注入。此时若是使用MoviesDirectedBy方法会致使NullReferenceException异常发生,由于lister实例仍然尚未对IMovieFinder的引用。注入到lister实例中的IMovieFinder接口实现的XML配置定义以下。
#001  ...
#002     <objects>
#003        ...
#004        <object name="MyMovieFinder"
#005       type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
#006        </object>
#007        ...
#008     </object>
#009  ...
(4)设值注入。下面要作的是把以MyMovieFinder为标识符的IMovieFinder实例注入到以MyMovieLister为标识符的MovieLister实例中。这个注入动做使用设值注入的方法,代码以下所示:
#001  ...
#002  <objects>
#003  <object name="MyMovieLister"
#004  type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
#005  <!-- using setter injection... -->
#006  <property name="movieFinder" ref="MyMovieFinder"/>
#007  </object>
#008  <object name="MyMovieFinder"
#009  type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
#010  </object>
#011  </objects>
#012  ...
当IApplicationContext接口取得了MyMovieLister对象之后,Spring.NET的IoC容器将会把对MyMovieLister对象的引用注入到MyMovieLister对象的MovieFinder属性中去。这样,在程序中引用的MovieFinder对象即配置完毕,能够列出某导演导过的全部电影。
#001  ...
#002  public static void Main ()
#003  {
#004  IApplicationContext ctx = ContextRegistry.GetContext();
#005  MovieLister lister = (MovieLister) ctx.GetObject ("MyMovieLister");
#006  Movie[] movies = lister.MoviesDirectedBy("Roberto Benigni");
#007  Console.WriteLine ("\nSearching for movie...\n");
#008  foreach (Movie movie in movies)
#009  {Console.WriteLine (
#010   string.Format ("Movie Title = '{0}', Director = '{1}'.",
#011   movie.Title, movie.Director));}
#012  Console.WriteLine ("\nMovieApp Done.\n\n");
#013  }
#014  ...
也可使用构造注入的方法,读者能够本身考虑构造注入方法的实现方式,这里就再也不具体介绍。
如今Spring.Net的1.0.2版本已经发布,读者能够经过访问[url]http://sourceforge.net/[/url] projects/ springnet下载。