之所以啓用spring.net,看中的是它的容器功能:一個可以管理對象整個生命週期的容器。在這個容器內,我們加入各種對象的定義信息,讓它們自動地裝配(類似於樂高積木,定製化的拼合)、實例化、事務協作、回收銷燬,以適應系統的需要。
如前所述,spring.net基於配置運作。要讓spring.net的容器感知我們編寫的對象,需要做的就是在配置文件中聲明它們。所謂配置,載體當然是xml文件,定義明晰,清清楚楚。
看一個xml配置片斷:
Code
〈?xml version="1.0" encoding="utf-8" ?>
〈objects xmlns="http://www.springframework.net"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"
>
〈!--controllers-->
〈object id="ArtistController"
type
="woodigg.controllers.Controllers.ArtistControllers, woodigg.controllers">
〈property name="ArtistDaoSpring" ref="ArtistDaoSpring" />
〈property name="PhotoDaoSpring" ref="PhotoDaoSpring" />
〈property name="MusicTypeDaoSpring" ref="MusicTypeDaoSpring" />
〈property name="GenreDaoSpring" ref="GenreDaoSpring" />
〈property name="StyleDaoSpring" ref="StyleDaoSpring" />
〈property name="AlbumDaoSpring" ref="AlbumDaoSpring" />
〈property name="TbrlSimilarDaoSpring" ref="TbrlSimilarDaoSpring" />
〈property name="TbrlInfluceDaoSpring" ref="TbrlInfluceDaoSpring" />
〈property name="TbrlFollowDaoSpring" ref="TbrlFollowDaoSpring" />
〈property name="AreaDaoSpring" ref="AreaDaoSpring" />
〈property name="TbrlGenreStyleDaoSpring" ref="TbrlGenreStyleDaoSpring" />
〈property name="CompanyDaoSpring" ref="CompanyDaoSpring" />
〈/object>
〈/objects>
解釋一下:這是一個並不複雜的控制器類ArtistController,我們聲明瞭它的id和type(類型,類在程序集中完整路徑及程序集名)。
這樣,spring.net的對象工廠(ObjectFactory或者ApplicationContext)在感知到對它的調用請求時,會實例化它並返回給需求方(可以是一個類,一個aspx頁面,一個asmx,或者別的什麼)——事實比這複雜得多,諸如你可以顯式地聲明它是單例的(加一個屬性 singleton="true",鄙人用的spring.net版本爲1.1.0.2),如此一來在spring.net容器生命週期內,它不會再有第二個實例,也許有時這會派上用場,能節省一些開銷。
繼續觀察,〈object>節內會有一些〈property>聲明,這是object的屬性聲明,name即它在內部對外公開的名稱,其後可以使用value(值),ref(引用對象)或者expression(表達式)。此例使用的ref引用,意味着容器將干涉內政——把需要的對象注入到object的字段裏,前提是:ref指定的對象存在於容器裝載的配置文件集合中,並以相同的id聲明。
勢必存在另一個配置,形如:
Code
〈?xml version="1.0" encoding="utf-8" ?>
〈objects xmlns="http://www.springframework.net"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"
>
〈!--業務相關-->
〈object id="ArtistDaoSpring" type="woodigg.DAO.ArtistDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="AdminDaoSpring" type="woodigg.DAO.AdminDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="CompanyDaoSpring" type="woodigg.DAO.CompanyDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="AreaDaoSpring" type="woodigg.DAO.AreaDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="AlbumDaoSpring" type="woodigg.DAO.AlbumDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="MusicTypeDaoSpring" type="woodigg.DAO.MusicTypeDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="GenreDaoSpring" type="woodigg.DAO.GenreDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="StyleDaoSpring" type="woodigg.DAO.StyleDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="FeelDaoSpring" type="woodigg.DAO.FeelDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="PhotoDaoSpring" type="woodigg.DAO.PhotoDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="TbrlSimilarDaoSpring" type="woodigg.DAO.TbrlSimilarDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="TbrlFollowDaoSpring" type="woodigg.DAO.TbrlFollowDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="TbrlInfluceDaoSpring" type="woodigg.DAO.TbrlInfluceDaoSpring,woodigg.DAO" autowire="byName" />
〈object id="TbrlGenreStyleDaoSpring" type="woodigg.DAO.TbrlGenreStyleDaoSpring,woodigg.DAO" autowire="byName" />
〈/objects>
在這個稍顯簡單的供求關係中,它們是供方,被需要、被別的對象引用,容器會在那個ref它們的對象(ArtistController)涉及到指定字段被使用時,提供其實例,比如ArtistController有個叫abc的方法中,用到了ArtistDaoSpring字段的defg()方法,容器接收到這一信息,裝配ArtistDaoSpring字段對應的woodigg.DAO.ArtistDaoSpring對象——你也許會說,直接實例化不就完了麼?呵呵,如果這個對象也是基於別的組件裝配出來的,那就不僅僅只是實例化一下,還是需要重複一下這個過程,遞歸着來,搭積木一般把它裝配成功交付需求方(像極了這個商業社會的產業鏈)。
在這裏,我們還看到一個屬性autowire,它可以有幾種枚舉選值(no,byName,byType,constuctor,autodetect,default),而byName的意思就是讓容器按名稱,自行查找同名的對象,進行裝配(id和類中的字段同名)。看到這裏,想必有人會說,你的第一個配置ArtistController,簡直就是廢話連篇,在object上指定autowire="byName"就行了,何必一個個指定property?bingo!如果不是爲了說明供求關係,我才懶得寫這些property,讓容器查找吧。
ok,以上皆爲務虛,來務實一把,裝配一個簡單.net對象(pono?)到一個.aspx頁面耍耍。
這個簡單對象RouteMap,是爲
Asp.net MVC
框架服務的——由於還無福使用WIN2008+IIS7,只得在.net 2.0下奮戰,對於new {action="Home",controller="Artist"}這麼瀟灑的範式自然也是隻能眼饞。沒關係!自己擴展吧:
Code
using
System;
/// 〈summary>
///
Asp.net mvc RouteMap
/// 〈/summary>
namespace
woodigg.controllers
{
public class
RouteMap
{
private string
_controller;
private string
_action;
private string
_id;
public string
Controller
{
get { return this
._controller; }
set { this._controller =
value; }
}
public string
Action
{
get { return this
._action; }
set { this._action =
value; }
}
public string
Id
{
get { return this
._id; }
set { this._id =
value; }
}
public RouteMap(string controller, string action, string
id)
{
this._controller =
controller;
this._action =
action;
this._id =
id;
}
}
}
RouteMap將被一個叫test.aspx頁面需要。它長這樣:
Code
using
System;
using
System.Data;
using
System.Configuration;
using
System.Collections;
using
System.Web;
using
System.Web.Security;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.UI.WebControls.WebParts;
using
System.Web.UI.HtmlControls;
public partial class
test : System.Web.UI.Page
{
#region 注入對象
private
woodigg.controllers.RouteMap _ArtistRoutmap;
public
woodigg.controllers.RouteMap ArtistRoutmap
{
get { return this
._ArtistRoutmap; }
set { this._ArtistRoutmap =
value; }
}
#endregion
protected void Page_Load(object
sender, EventArgs e)
{
Response.Write(ArtistRoutmap.Controller);
}
}
它會在頁面加載完成時,輸出這個RouteMap的控制器名稱。至於這東西到底從哪來的值,沒有說明。那麼,就爲這倆構造一個配置,由容器來裝配它們。
新建一個routemap.xml文件,放在網站的~/config目錄下,形如:
Code
〈?xml version="1.0" encoding="utf-8" ?>
〈objects xmlns="http://www.springframework.net"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"
>
〈!--routemap-->
〈object id="ArtistRoutmap" type="woodigg.controllers.RouteMap,woodigg.controllers">
〈constructor-arg name="controller" value="Artist" />
〈constructor-arg name="action" value="Home" />
〈constructor-arg name="id" value="3" />
〈/object>
〈!--頁面-->
〈object type="~/test.aspx" autowire="byName" />
〈/objects>
ArtistRoutmap在被實例化時,我們希望它是有默認值的,在配置中逐一指定它構造函數參數項的值,這很好理解。
頁面對象的聲明更簡單,只需說明它在站點中存在的路徑,字段引用按名稱查找吧。
累述至此,對象裝配已經完成,但要讓容器自動的運轉起來,還需要在站點層面做些配置:
1、引用spring.net程序集及相關(以1.1.0.2爲例,如有出入,稍爲調整),包括:Spring.core.dll,Spring.web.dll,Spring.Web.Extensions.dll,log4net.dll;
2、修改web.config,裝載Spring模塊和處理程序,並指定配置上下文路徑,裝載日誌系統:
Code
〈?xml version="1.0"?>
〈configuration>
〈configSections>
〈sectionGroup name="spring">
〈section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
〈section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
〈/sectionGroup>
〈section name="SpringOverrideProperty" type="System.Configuration.NameValueSectionHandler"/>
〈section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
〈!--log4net-->
〈section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
〈/configSections>
〈SpringOverrideProperty>
〈add key="DbProvider.ConnectionString" value="Data Source=(local);Database=Music;User ID=sa;Password=system;Trusted_Connection=False"/>
〈add key="SystemInit.IsDebug" value="true"/>
〈add key="SystemInit.Level" value="4"/>
〈/SpringOverrideProperty>
〈!-- Spirng.Net 配置 -->
〈spring>
〈context>
〈resource uri="config://spring/objects"/>
〈resource uri="~/config/routemap.xml"/>
〈/context>
〈objects xmlns="http://www.springframework.net"/>
〈/spring>
〈log4net>
〈!-- log4net的配置節 -->
〈appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net">
〈param name="File" value="log//log_.txt"/>
〈param name="AppendToFile" value="true"/>
〈param name="RollingStyle" value="Date"/>
〈param name="DatePattern" value="yyyy.MM.dd"/>
〈param name="StaticLogFileName" value="true"/>
〈layout type="log4net.Layout.PatternLayout,log4net">
〈param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"/>
〈/layout>
〈/appender>
〈root>
〈priority value="ALL"/>
〈level value="ERROR"/>
〈appender-ref ref="rollingFile"/>
〈/root>
〈/log4net>
〈system.web>
〈httpModules>
〈add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
〈/httpModules>
〈httpHandlers>
〈add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
〈add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web"/>
〈/httpHandlers>
〈httpRuntime maxRequestLength="1000000" executionTimeout="300"/>
〈/system.web>
〈/configuration>
添一個全局配置Global.asax,在啓動時開啓日誌記錄:
Code
void Application_Start(object
sender, EventArgs e)
{
// log4net
log4net.Config.DOMConfigurator.Configure();
}
run一下這個test.aspx,它會輸出控制器名稱"Artist",平平無奇,卻是與一種方式的告別——Craig Walls們在《Action in Spring》的序中這樣寫道:開發者有一種寶貴的品質,那就是“懶惰”。這種懶惰激勵開者努力用最小的開銷找到最佳的解決方案。
其實,有時不需要那麼勤勞的,有些東西用成熟的框架能很好的解決,何必自己造輪子呢?