之所以启用spring.net,看中的是它的容器功能:一个可以管理对象整个生命周期的容器。在这个容器内,我们加入各种对象的定义信息,让它们自动地装配(类似于乐高积木,定制化的拼合)、实例化、事务协作、回收销毁,以适应系统的需要。
之所以启用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》的序中这样写道:开发者有一种宝贵的品质,那就是“懒惰”。这种懒惰激励开者努力用最小的开销找到最佳的解决方案。
其实,有时不需要那么勤劳的,有些东西用成熟的框架能很好的解决,何必自己造轮子呢?当然,我并不是来搞推销的,只是由衷的喜欢spring,仅此而已。
至于web service页.asmx的注入,将会在以后交待,或者有兴趣也可以参看一下这个不错的中文文档:
https://files.cnblogs.com/moye/SpringNet_document.rar
也可以常上官网看看:http://www.springframework.net/
抑或与同好们交流:http://www.springframework.cn/index.php