Spring ActionScript入门教程
Spring ActionScript入门教程(1)-简介
这是一个系列文章,总共3篇,RIAMeeting将在这3篇文章中为大家讲述Spring ActionScript的基本概念以及使用方法,通过学习这3篇文章,开发者可以创建出一个简单的Spring ActionScript的应用,并体会到Spring ActionScript带来的优势和便捷性。
当然,基本上所有的框架的最大价值在于它给你的结构上的规范和指导意义,所以我们在使用框架的时候,应当尽量去体会框架对于自己编程思想的提升,如果只是为使用框架而是用框架,就会感觉框架繁琐而且加大工作量,增加编码体积,实际上框架的最大优势都是在后期才体现出来的(比如当项目趋于扩大化时的维护,管理和团队协作)。
Part1:介绍Spring ActionScript
首先,我们先来介绍一下Spring ActionScript,如果你来自Java社区,应该对Spring并不陌生,实际上在Java社区中Spring作为替代J2EE的一个轻量级的框架有着非常广泛的应用。Spring包含两个方面的重要功能:IoC和AOP,大家用到Spring最多的地方实际上也是IoC。另一个方面AOP面向切面在AS中不被支持。简单的说,Spring ActionScript是Spring在ActionScript中的实现。
名词解释:
IoC:控制翻转(inverse of control),Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传 递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就 主动将依赖传递给它。
DI:Dependency Injection (DI),即依赖注入。
Part2:安装Spring ActionScript Framework
在这里以Flash Builder4为例说明如何安装Spring ActionScript Framework。Flash Builder是Flex Builder的最新版本(从4的版本开始更名为Flash Builder)目前还是Beta版,但它从各方面来说都比Flex Builder3提升了不少,所以我们这里使用Flash Builder4以提升编程的效率。
言归正传,如果我们需要安装为Flash Builder安装Spring ActionScript Framework,需要遵循以下的步骤:
- 安装Flash Builder4,你可以从Adobe的网站(http://labs.adobe.com)下载Flash Builder4的安装文件,这个过程非常简单,界面也非常容易使用,因为Flash Builder是基于Eclipse的。
- 创建一个新项目,或者导入原有的Flex Builder3的项目
- 下载Spring ActionScript Framework的SWC文件,下载地址在本文的最底部
- 下载依赖的第三方SWC文件,因为这个项目依赖了很多第三方的类库,所以需要你把这些依赖的类库也都下载下来,这些类库包括:as3commons-reflect.swc , as3commons-lang.swc , as3commons-logging.swc , flexunit.swc,这些都在最底部的压缩文件中被包含,下载即可
- 将所有下载的SWC文件移动到你的项目的Libs目录,然后你需要修改编译参数,将这些类库编译到SWF中去,步骤是:打开项目属性面板,定位到Flex Compiler选项,找到additional compiler arguments,输入类似于下面的语句:-locale en_US -default-background-color #000000 -include-libraries ../libs/spring-actionscript.swc ../libs/as3commons-reflect.swc ../libs/as3commons-lang.swc ../libs/as3commons-logging.swc ../libs/flexunit.swc
参见图片说明,点击查看大图:
在上面我们稍感麻烦的一点是还要手工把所有的依赖的SWC编译进去,否则运行时会找不到依赖的库,一旦项目依赖的库比较多,这个配置代码就会很长,也会给部署的人带来麻烦,针对这种情况,Maven有非常好的解决方法,参见RIAMeeting关于Maven的介绍文章:
- http://www.riameeting.com/node/445
- http://www.riameeting.com/node/446
- http://www.riameeting.com/node/447
Spring ActionScript 允许你使用XML描述文件来定义你需要在应用中使用的实例以及它们之间的相互依赖关系。这个XML文件可以是一个外部的XML文档,也可以是一个内嵌的 XML(嵌入到Flex的MXML中作为元数据存在)。这两种方式都被支持,只是在使用上稍有区别。
非常需要注意的是在Flex中使用Spring,必须要保证被依赖的类被编译到SWF中,否则会报运行时错误(无法找到所需的类),解决方法参加Part2的编译器参数部分。
下面我们来讨论如何编写Spring的配置文件,这个配置文件遵循XML结构,我们先来看一个典型的配置文件,你可以打开你的Flash Builder4,然后新建一个文本文件,命名为"application_context.xml",然后粘贴下面的代码片段到这个文件中:
- <objects>
- <import file="services.xml"/>//行1
- <import file="resources/messageSource.xml"/>//行2
- <import file="/resources/themeSource.xml"/>//行3
- <object id="object1" class="..."/>//行4
- <object id="object2" class="...">//行5
- <property name="elements" value="123456" />//行6
- </object>
- </objects>
对于熟悉XML的朋友,这段配置非常容易理解,主要包含以下几个方面:
- 支持导入xml文件(参加行1,2,3),就是说,我们可以按照一定的规则拆解XML中的内容到不同的文件,以便于管理和维护,方法是使用import标签
- 实例化一个对象,使用object标签(参见行4,行5),其中有两个必须的属性,即id和class,id代表对这个object的引用,class代表这个object对应的类,注意要写全类名和包路径,比如:class="mx.containers.Panel"
- 使用property属性定义这个object的依赖(参见行6),比如这个object需要的一些字符串类型的数据,以及对另外一个对象的引用等等,如果是直接赋值,使用value,引用则使用ref
我们还可以使用定义外部变量(常量)的方式,将一些配置方面的信息以变量或常量的形式定义在外部,以便于部署和维护时候的修改,通常我们会建立一个类似于prop.properties这个的一个文本文件,然后使用下面的变量声明方式来声明变量:
- s1=First string
- s2=Second string
在XML中引用,使用${s1}的方式来引用:
- <objects>
- <property file="strings.properties" />
- <object id="string1" class="String">
- <constructor-arg value="${s1}"/>
- </object>
- <object id="string2" class="String">
- <constructor-arg value="${s2}"/>
- </object>
- </objects>
还可以在一个对象的内部使用内联对象,举例:
- <object id="outer" class="...">
- <property name="target">
- <object class="com.example.Person">
- <property name="name" value="Fiona Apple"/>
- <property name="age" value="25"/>
- </object>
- </property>
- </object>
下表是在配置文件中常用的一些标签以及相关的说明和用法
术语 说明 代码示例 ${变量名} 你可以把一些变量分离出来写在单独的文本文件中,然后在配置中引用这些变量,这样最大的好处是你可以把配置信息比如Server端的连接地址放在单独的文件中,方便修改和维护
新建global.prop文本文件,写入:
variable1=10
在配置中引用:
${variable1}
object 在XML配置中,每一个对象用Object来表示,然后分别用id和class代表唯一标示和类的名称 <object id="obj" class="mx.ctrol.Button" /> property 你可以使用property为对象的属性复制,这也是IoC的精髓,即从这里把依赖注入到对象。name就是属性的名称,而value就是你要赋予的具体的值
<object ... >
<property name="name" value="Fiona Apple"/>
</object>
ref 除了可以直接赋值,你也可以通过使用ref在属性中引用别的对象
<object id="a" .../>
<object ... >
<property name="name" ref="a"/>
</object>
constructor-arg 如果你的对象实例化的时候需要从构造函数中传入参数,那么可以使用这个属性,将所需的参数传递进去
<object ... >
<constructor-arg>
<ref>anotherExampleObject</ref>
</constructor-arg>
<constructor-arg type="int" value="1"/>
</object>
factory-method 工厂方法,含义是不使用new对这个Object进行实例化,而是调用这个类的静态方法,可用于单例模式的实现 <object id="a" class="A" factory-method="getInstance" /> dictionary 相当于AS3中的Dictionary,你可以在配置中声明一个Dictionary对象 <dictionary>
<entry>
<key>development</key>
<value>dx</value>
</entry>
</dictionary> array 同样,你可以在配置中声明一个数组对象 <array>
<value>ssnce</value>
<value><ref object="s"/></value>
</array> array-collection 对应Flex中的ArrayCollection,当然只有Flex的应用才可以使用这个配置方式 <array-collection>
<value>ssnce</value>
<value><ref object="s"/></value>
</array-collection> depends-on 定义依赖关系,含义就是先初始化它的依赖,然后初始化自己 depends-on="manager,accountDao" lazy-init 如果值为true,则不马上初始化,而是在第一次调用的时候才初始化 <object ... lazy-init="true"/> autowire
自动装配,Spring ActionScript支持自动装配,含义就是你只要声明某个对象为自动装配,它就会按照规则自动去寻找这个对象的依赖并注入给它,而不需要手工操作。
默认是no,可以选择byName,byType,constructor,autodetect来自动装配对象的依赖。使用自动装配时,应当权衡利弊,合理的与ref的方法相结合,尽量在降低工作量的同时,保证应用的可维护度
<object ... autowiret="byName"/> singleton 一个布尔量,对一个对象而言,这个属性的设置为True则只创建一个实例,false则每次调用都创建新的实例 <object ... singleton="true"/> init-method 初始化方法,含义是创建实例后,调用实例的这个方法进行初始化 init-method="init" method-invocation 调用对象的方法 <method-invocation name="init"/> abstract 定义继承关系,你可以将一个对象的abstract属性设置为true,然后在另一个对象中定义parent=这个对象,含义就是继承原对象的所有的属性 <object id="inheritedTestObject" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</object>
<object id="inheritsWithDifferentClass"
class="org.springactionscript.objects.DerivedTestObject"
parent="inheritedTestObject" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</object> template 你可以将重复性的设置工作定义为模板,然后其它对象就可以使用这个模板 <template id="remoteObject">
<object class="mx.rpc.remoting.mxml.RemoteObject">
<property name="makeObjectsBindable" value="${makeBindable}"/>
</object>
</template>
<object id="concreteService" template="remoteObject">
<param name="makeBindable" value="false"/>
</object> application Flex专属属性,你可以通过配置下面这个对象:<object class="org.springextensions .actionscript.ioc. factory. config.flex. ApplicationPropertiesResolver"/>,然后就可以在其他的配置中使用application这个变量,使用方式是:${application.url}
- application.frameRate
- application.historyManagementEnabled
- application.pageTitle
- application.resetHistory
- application.scriptRecursionLimit
- application.scriptTimeLimit
- application.url
- application.url.protocol
- application.url.host
- application.url.port
- application.usePreloader
- application.viewSourceURL
上面我们讨论如何编写一个配置文件,然后我们看一下如何在Flex中载入并解析这个文件。
首先需要了解的是,我们如果要在Flex中使用DI注入对象,需要使用一个IoC容器来做这件事。FlexXMLApplicationContext 或 XMLApplicationContext 是Spring关于IoC的基础容器。两者基本相同,第一个只是增加了对Flex的支持,比如ArrayCollection。一般也认为这是程序的入 口,我们写代码的开始会用到这两个类,用于载入和分析配置文件(XML)。
使用容器载入配置的代码示例:
- var applicationContext:XMLApplicationContext
- = new XMLApplicationContext();
- applicationContext.addConfigLocation("application-context.xml");
- applicationContext.addEventListener(Event.COMPLETE, handleComplete);
- applicationContext.load();
Spring ActionScript入门教程(2)-一个简单的实例
在这个部分,我们来使用前一章学到的知识,建立一个简单的Spring ActionScript的应用。你可以认为这是学习Spring ActionScript的一个类似于“Hello World”的例子,在这个例子里,我们将创建一个简单的列表,来显示一些模拟的数据,好,让我们开始下一步的操作。
图1:实例界面截图
准备工作
- 安装Flex Builder
- 准备好XML编辑工具,因为Spring ActionScript中依赖XML来描述结构,所以一个好用的XML编辑器是必不可少的,你可以为Flex Builder安装XMLBuddy插件,也可以使用Notpad++等独立的文本编辑器
首先打开Flex Builder3 (当然也可以是Flash Builder4),创建一个新项目(Flex项目),命名为“SpringActionScriptDemo”,其它保持默认,直接点击“Finish”完成,短暂的时间过后,Flex Builder就为你创建了一个空项目,并且创建了一个SpringActionScriptDemo.mxml的程序文件,在编辑器中处于打开状态。
编辑器中的代码应该如下面所示:
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
- </mx:Application>
当然这只是一个空的Application,里面什么也没有,然后我们需要做的是,把Spring ActionScript的类包SWC文件引入进来,找到上个章节中提供下载的压缩包,解压后你会看到若干的SWC文件,将这些文件转移到你的项目中的libs目录,这个目录是默认的项目引用库,放在这里是为了让你的代码可以引用到这些类包。
转移好之后,你的libs目录看起来应该是这个样子:
图2:Libs结构
然后我们将在src目录下面建立一些文件。下面的步骤如无特殊说明,新建文件都基于src目录,这里因为文件足够少而且简单所以没有分目录存放,实际上一个正式的项目的文件复杂度远大于此,需要仔细拆分和优化目录结构。
首先我们建立一个命名为“global.prop”的文本文件,用来存放全局的一些变量,这里我们先存放一下界面的标题,输入以下的文本:
siteName=test site
因为这个应用要显示一些虚拟的数据,所以我们建立一个命名为"data.xml" 的XML文件,并输入下面的内容:
- <objects>
- <object id="myData" class="mx.collections.ArrayCollection">
- <constructor-arg>
- <array>
- <value>Zhang San</value>
- <value>Li Si</value>
- <value>Wang wu</value>
- <value>11111</value>
- <value>22222222222</value>
- <value>33333333333</value>
- </array>
- </constructor-arg>
- </object>
- </objects>
XML内容分析:我们可以看到,我在里面声明了一个object,id是myData,这个一会儿我们就会引用到,类别是ArrayCollection(ArrayCollection是Flex的一种数据集合),然后通过使用construtor-arg传递一个数组对象进去,实现了给ArrayCollection赋值。
下面建立最重要的一个XML配置文件,命名为”appliction-context.xml“,输入下面的内容:
- <objects>
- <property file="global.prop"/>
- <import file="data.xml"/>
- <object id="container" class="mx.containers.Panel">
- <property name="title" value="${siteName}" />
- <method-invocation name="addChild">
- <arg ref="myList" />
- </method-invocation>
- </object>
- <object id="myList" class="mx.controls.List">
- <property name="width" value="500" />
- <property name="height" value="500" />
- <property name="dataProvider" ref="myData" />
- </object>
- </objects>
XML分析:第一行和第二行分别引入了变量文件和定义数据的XML文件,然后我们定义了两个显示对象,一个是Panel,一个是List。我们设置了List的一些属性,包括定义dataProvider,引用了在data.xml中定义的myData的数据,然后我们调用了Panel的addChild方法,将List放到Panel中。
到这里XML部分的配置工作就做好了,下面我们来看如何在Flex中载入并解析这些配置文件:
回到SpringActionScriptDemo.mxml,建立一个代码块儿,然后输入建立IoC容器的代码,之后整体的代码应该如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" layout="absolute">
- <mx:Script>
- <![CDATA[
- import org.springextensions.actionscript.context.support.FlexXMLApplicationContext;
- private var context:FlexXMLApplicationContext;
- private function init():void {
- var appContextPath:String = "application_context.xml";//定义xml的地址
- context = new FlexXMLApplicationContext(appContextPath);//创建一个IoC容器
- context.addEventListener(Event.COMPLETE,onIoCLoadComplete);//添加事件侦听器,侦听完成事件,执行回调
- context.load();//加载配置文件
- }
- private function onIoCLoadComplete(e:Event):void {
- addChild(context.getObject("container"));//加载配置结束后,将 container容器(即Panel)添加到显示列表
- }
- ]]>
- </mx:Script>
- </mx:Application>
按下F11键,调试项目,怎么样,是否看到一个显示数据的列表了?
好了,到这里一个简单的Spring ActionScript的例子就完成了,我们将在下一个章节中深入探讨如何结合Cairngorm,这样才能适应一个大型项目的开发流程。
附件中是本实例的源码。
spring---实现项目:RSS阅读器
接下来的内容,我们假定项目需求是实现一个RSS阅读器,这个阅读器只需实现载入并分析Feed地址,显示Feed内容即可,在这个项目中我们将综合使用Spring ActionScript和Cairngorm。
另外这个实例需要你安装Flex Builder3或者Flash Builder4,你可以在Adobe的站点下载到这些IDE。请事先了解这些IDE的基本操作知识,本文假定您已经具备了使用Flex Builder的基本技巧,在操作环节上不会做过于细致的介绍。
Part1 新建项目
首先打开Flex Builder,创建两个项目:
- 第一个项目,名为“SpringActionScriptCairngormDemo”,类型是Flex项目,保持默认选项,直接点击Finish完成项目创建。
- 第二个项目,名为“SpringActionScriptCairngormDemoLib”,注意类型是Flex库项目(Flex Library Project)。
这里介绍一下为什么要创建两个项目,第一个项目是我们要用的主项目,在这个项目中我们将使用IoC容器,使用反射的机制根据配置文件从SWF中找到所需的类并实例化,这就需要最终编译的SWF文件中应当包含所有用到的类(Flex类库和项目自己的类库),如果我们将项目自己的类库也作为SWC形式存在将非常有利于编译到主SWF,这也是第二个Lib项目存在的原因;第二个项目做为一个库项目存在,包含了这个RSS阅读器项目的主体代码和实现,我们的主要代码工作也是在这个Lib库里面,第一个项目只是完成最终的装配工作。
Part2 配置libs
同前一章类似,我们也需要将项目依赖的SWC文件放到项目的libs目录以便编译时引用,请先下载下面的压缩包:
http://www.riameeting.com/files/libs_0.rar
下载后解压,你会看到一些SWC文件。
对于项目“SpringActionScriptCairngormDemo”,直接将这些文件拷贝到这个项目的libs目录中即可。
对于项目“SpringActionScriptCairngormDemoLib”,因为这个库项目本身不包含libs目录,我们需要在项目中手工创建这样一个目录,拷贝SWC文件到这个目录中,然后对项目做一下设置,在Build Path部分加入这个包含SWC的目录:
图2:Flex Library Build Path
Part3 实现SpringActionScriptCairngormDemoLib
在第三部分我们来实现Lib项目的编码,让我们回到“SpringActionScriptCairngormDemoLib”项目。
3.1 构建MVC目录结构
这个项目是基于MVC架构的,那么我们首先完成一些目录结构的创建,在src目录下,先创建包com.riameeting,(即先创建一个目录com,然后在com里创建一个目录riameeting),在riameeting目录中创建以下的目录结构,注意中文部分是说明文字:
- business 这个目录用于存放服务的代理,代理将组件与服务之间进行了解耦
- command 这个目录用于存放命令,在MVC结构中通常命令承担主要的逻辑控制工作
- event 存放自定义事件
- factories 这个目录用于存放工厂类,工厂类将承担一部分的组装工作
- model 存放数据模型,通常将MVC结构中的ModelLocator放在这个目录下
- utils 存放自定义的一些支持项目的类
- view 存放视图
首先我们先设计好项目的数据模型,对这个项目来说,基本上数据就是两个:Feed地址,和Feed的XML内容,那么我们先声明一个接口,定义对这两条数据的存放。
在model下创建一个接口,名为IApplicationModel,并声明获取Feed地址和Feed内容的方法:
- package com.riameeting.model
- {
- import mx.collections.XMLListCollection;
- [Bindable]
- public interface IApplicationModel
- {
- //
- function get feedURL():String;
- function set feedURL(url:String):void;
- //
- function get feedList():XMLListCollection;
- function set feedList(dataList:XMLListCollection):void;
- }
- }
创建类ApplicationModel,实现接口IApplicationModel,并使用单例模式。
- package com.riameeting.model
- {
- import mx.collections.XMLListCollection;
- [Bindable]
- public class ApplicationModel implements IApplicationModel
- {
- public function ApplicationModel(enforcer:SingletonEnforcer){}
- private static var me:ApplicationModel;
- public static function getInstance():ApplicationModel {
- if(me==null) {
- me = new ApplicationModel(new SingletonEnforcer);
- }
- return me;
- }
- private var _feedURL:String;
- public function get feedURL():String
- {
- return _feedURL;
- }
- public function set feedURL(url:String):void
- {
- _feedURL = url;
- }
- private var _feedList:XMLListCollection;
- public function get feedList():XMLListCollection
- {
- return _feedList;
- }
- public function set feedList(dataList:XMLListCollection):void
- {
- _feedList = dataList;
- }
- }
- }
- class SingletonEnforcer{}
我们在创建一个接口,IApplicationModelAware,这个接口的设计含义是,如果其它的类需要在自己内部定义ApplicationModel并等待IoC来注入,就可以实现这个接口,比如我有个Command类,可以实现这个接口来在内部定义ApplicationModel,虽然实际上我也可以通过ApplicationModel.getInstance()的方法获取Model的实例,但这样会造成你的类对ApplicationModel类产生直接的依赖,这就形成了耦合,并且非常不利于单元测试,合理的做法应该是通过IoC将Model注入到你的类,而不是你的类主动去寻找Model。
IoC的理念可以总结为:不要来找我,需要的时候我会给你。
- package com.riameeting.model
- {
- public interface IApplicationModelAware
- {
- function get applicationModel():IApplicationModel;
- function set applicationModel(value:IApplicationModel):void;
- }
- }
3.3 创建自定义事件
在event目录下,我们来定义事件。如果你了解Cairngorm的一些知识,就会知道Cairngorm的基本逻辑控制都是通过事件与命令之间的映射来完成的。这里我们来定义一个事件,命名为GetFeedEvent,如果系统想获取Feed信息,只要派发这个事件即可,这个事件会被前端控制器(FrontControler)映射到一个具体的命令上。
- package com.riameeting.event
- {
- import com.adobe.cairngorm.control.CairngormEvent;
- public class FeedEvent extends CairngormEvent
- {
- public static var GET_FEED_EVENT:String = "getFeedEvent";
- public function FeedEvent(type:String)
- {
- super(type, true, true);
- }
- }
- }
spring---实现项目:RSS阅读器(二)
3.4 构建视图在view目录下,这里我们构建两个视图,在Flex的角度考虑,其实就是构建两个MXML组件(Components),组件一是一个地址栏,允许用户输入一个Feed地址,然后按下按钮去获取Feed信息;组件二是一个列表,用于显示Feed的RSS内容,这里我们可放一个List组件,列出RSS的所有内容,并自定义项目渲染器,用标题加摘要的形式来显示RSS的一条内容。
组件一:AddressBar.mxml
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="40">
- <mx:Script>
- <![CDATA[
- import com.riameeting.event.FeedEvent;
- import com.riameeting.model.IApplicationModel;
- [Bindable]
- public var model:IApplicationModel;
- private function onClick():void {
- model.feedURL = txt.text;
- var getFeedEvent:FeedEvent = new FeedEvent(FeedEvent.GET_FEED_EVENT);
- getFeedEvent.dispatch();
- }
- ]]>
- </mx:Script>
- <mx:TextInput id="txt" text="{model.feedURL}" x="10" y="10" width="331"/>
- <mx:Button x="349" y="10" label="Go" click="onClick()"/>
- </mx:Canvas>
组件二:SearchResult.mxml
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="400">
- <mx:Script>
- <![CDATA[
- import com.riameeting.model.IApplicationModel;
- [Bindable]
- public var model:IApplicationModel;
- ]]>
- </mx:Script>
- <mx:List x="10" y="10" dataProvider="{model.feedList}" width="380" height="380">
- <mx:itemRenderer>
- <mx:Component>
- <mx:Box width="100%" height="100" horizontalScrollPolicy="off" verticalScrollPolicy="off">
- <mx:Label text="{data.title}" fontWeight="bold"/>
- <mx:Text htmlText="{data.description}"/>
- </mx:Box>
- </mx:Component>
- </mx:itemRenderer>
- </mx:List>
- </mx:Canvas>
3.5 实现代理
在business目录下,我们来实现服务的代理。通常一个Cairngorm应用的形式是,将Command和Service隔离,Command通过调用代理,而代理调用Service来获取数据。经过考虑,我们这个代理所需要的方法就是一个获取Feed的方法,那么我们首先声明接口,如果其它的类(比如Command)要调用代理,那么只需要通过接口了解方法即可,而不需要了解具体的代理类如何实现。
创建接口IGetFeedDelegate
- package com.riameeting.business
- {
- import org.springextensions.actionscript.cairngorm.business.IBusinessDelegate;
- public interface IGetFeedDelegate extends IBusinessDelegate
- {
- function getFeed(url:String):void;
- }
- }
然后创建代理类GetFeedDelegate来实现这个接口,并继承AbstractBusinessDelegate,这是一个抽象代理,包含了一些代理所需的基本属性。
- package com.riameeting.business
- {
- import mx.rpc.AsyncToken;
- import mx.rpc.IResponder;
- import org.springextensions.actionscript.cairngorm.business.AbstractBusinessDelegate;
- public class GetFeedDelegate extends AbstractBusinessDelegate implements IGetFeedDelegate
- {
- public function GetFeedDelegate(service:Object=null, responder:IResponder=null)
- {
- super(service, responder);
- }
- public function getFeed(url:String):void {
- service.url = url;
- var token:AsyncToken = service.send();
- token.addResponder(this.responder);
- }
- }
- }
spring---实现项目:RSS阅读器(三)
3.6 实现Command
在command目录,我们来创建命令,在Cairngorm中,命令承担着绝大多数的代码工作,我们需要定义一个命令,来获取Feed的内容,一旦有事件触发这个命令,这个命令就执行并调取代理来获取数据。
不过首先我们需要创建一个命令的基类,命名为CommandBase,这个基类的目的是在命令中预先声明对ApplicationModel的定义,其它所有的命令都基于这个命令来扩展,则所有的命令都具备ApplicationModel属性,这就意味着所有的命令都在实例化的时候已经知道Model是什么,而不需要自己去寻找Model。
package com.riameeting.command{ import com.riameeting.model.IApplicationModel; import com.riameeting.model.IApplicationModelAware; import org.springextensions.actionscript.cairngorm.commands.AbstractResponderCommand; public class CommandBase extends AbstractResponderCommand implements IApplicationModelAware { public function CommandBase() { super(); } private var _applicatinModel:IApplicationModel; public function get applicationModel():IApplicationModel { return _applicatinModel; } public function set applicationModel(value:IApplicationModel):void { _applicatinModel = value; } }}
然后实现我们所需的获取Feed的命令,命名为GetFeedCommand:
package com.riameeting.command{ import com.adobe.cairngorm.control.CairngormEvent; import com.riameeting.business.IGetFeedDelegate; import mx.collections.XMLListCollection; import mx.controls.Alert; /** * 对这个Command来说,不需要自己去找Model,Delegate,IoC容器会为它注入 * */ public class GetFeedCommand extends CommandBase { import mx.managers.CursorManager; override public function execute(event:CairngormEvent):void { super.execute(event); IGetFeedDelegate(this.businessDelegate).getFeed(applicationModel.feedURL); CursorManager.setBusyCursor(); } override public function result(data:Object):void { CursorManager.removeBusyCursor(); var x:XML = new XML(data.result.toString()); applicationModel.feedList = new XMLListCollection(x.channel.item); trace(applicationModel.feedList.toXMLString()); } override public function fault(info:Object):void { Alert.show(info.toString(),"fault"); } }}
3.7 实现工厂类
这里我们首先引入一个问题,对于Command,我们希望将代理和Model都通过IoC注入给它,对于代理,我们也希望将Service注入进去,这都体现了IoC的设计原则,即这些注入工作都有IoC容器来完成,项目中的每个类只需要专注于自己功能的实现,而不需要自己去寻找外部依赖,所有的依赖都由IoC容器来负责注入。对于View我们可以声明属性并通过XML配置来注入,但对于Command这样只有在Event触发的时候才创建的实例,我们需要用特殊的机制来为它们注入依赖。这里我们就需要实现一个工厂类ApplicationModelAwareCommandFactory,这个工厂将取代Cairngorm默认的Command实例化方式,在Command实例化的时候同时注入依赖。
在factories目录中,创建类ApplicationModelAwareCommandFactory:
package com.riameeting.factories{ import com.adobe.cairngorm.commands.ICommand; import com.riameeting.command.CommandBase; import com.riameeting.model.IApplicationModel; import com.riameeting.model.IApplicationModelAware; import org.as3commons.reflect.ClassUtils; import org.springextensions.actionscript.cairngorm.commands.ICommandFactory; import org.springextensions.actionscript.cairngorm.commands.ResponderCommandFactory; public class ApplicationModelAwareCommandFactory extends ResponderCommandFactory implements ICommandFactory, IApplicationModelAware { private var _applicationModel:IApplicationModel; public function ApplicationModelAwareCommandFactory() { super(); } override public function canCreate(clazz:Class):Boolean { if (ClassUtils.isSubclassOf(clazz, CommandBase)) { return super.canCreate(clazz); } return false; } override public function createCommand(clazz:Class):ICommand { var result:CommandBase = super.createCommand(clazz) as CommandBase; result.applicationModel = _applicationModel; return result; } public function get applicationModel():IApplicationModel { return _applicationModel; } public function set applicationModel(value:IApplicationModel):void { _applicationModel = value; } }}
3.8 实现工具类ApplicationViewAssembler
因为IoC只负责实例化对象,并不负责为你加入显示列表,所以我们来实现一个工具类ApplicationViewAssembler,它的作用就是作为一个处理显示对象的容器,负责将这些显示对象添加到显示列表。将这个类保存在utils目录中。
package com.riameeting.utils{ import flash.display.DisplayObject; import mx.core.Application; import mx.core.FlexSprite; public class ApplicationViewAssembler { public function ApplicationViewAssembler(){} public var elements:Array; public function init():void{ for (var i:int = 0 ; i < elements.length ; i++){ (Application.application as FlexSprite).addChild(elements[i] as DisplayObject); } } }}
至此Lib部分的编码结束了,你可以编译一下,看bin目录下面是不是生产SWC文件了,在下半部分我们将在主体项目中引入这个Lib项目,并通过IoC容器装配出一个可用的RSS阅读器。
Spring ActionScript入门教程(3)-Spring和Cairngorm的结合使用[下]
本文接上一部分继续完成RSS阅读器实例,在上个部分中我们完成了Lib项目的构建,其实已经基本上完成了项目本身的逻辑代码,而在这一部分,我们将把这个Lib引入到IoC框架中,并编写相应的XML配置文件,最终完成装配,形成完整的应用。
Part4 实现主项目SpringActionScriptCairngormDemo
让我们回到SpringActionScriptCairngormDemo,开始完成IoC的注入工作。
4.1 配置编译参数
打开项目属性,在编译参数部分,将项目依赖的SWC文件都设置好,包括两部分:一部分是已经下载到libs目录下的SWC文件,还要把我们上个例子中编译好的SpringActionScriptCairngormDemoLib.swc也配置进去,配置参数应该如下:
-locale en_US -default-background-color #000000 -include-libraries ../libs/spring-actionscript.swc ../libs/spring-actionscript-cairngorm.swc ../libs/as3commons-reflect.swc ../libs/as3commons-lang.swc ../libs/as3commons-logging.swc ../libs/flexunit.swc ../../SpringActionScriptCairngormDemoLib/bin/SpringActionScriptCairngormDemoLib.swc
参见附图:
4.2 写配置XML
在src目录下,创建一个文件夹名为“config”,然后在config下面再创建两个目录,分别是cairngorm和view,第一个目录是为了存放和Cairngorm相关的配置,第二个目录是用于存放跟视图相关的配置。当然这样拆分目录是为了便于区分和维护,实际上你也可以根据需要按照自己的需要拆分目录结构,IoC对此没有硬性要求。
首先我们先来配置Cairngorm的部分,将Cairngorm部分必须的Service,ModelLocator,FrontControler等部分一一做配置。在cairngorm目录下,创建一个XML文件,名为“cairngorm.xml”。输入下面的内容:
- <objects>
- <!--ModelLocator-->
- <object id="appModelInstance" class="com.riameeting.model.ApplicationModel" factory-method="getInstance" singleton="true">
- <property name="feedURL" value="http://www.riameeting.com/rss.xml" />
- </object>
- <!--Service Locator-->
- <object id="serviceLocator" class="org.springextensions.actionscript.cairngorm.business.CairngormServiceLocator" factory-method="getInstance">
- <property name="feedService">
- <ref>feedService</ref>
- </property>
- </object>
- <object id="feedService" class="mx.rpc.http.HTTPService">
- <property name="url" value="http://www.riameeting.com/rss.xml"/>
- <property name="method" value="GET"/>
- <property name="useProxy" value="false"/>
- <property name="resultFormat" value="text"/>
- </object>
- <!--Delegate Factory-->
- <object id="businessDelegateFactory" class="org.springextensions.actionscript.cairngorm.business.BusinessDelegateFactory">
- <property name="service" ref="feedService"/>
- <property name="delegateClass" type="class" value="com.riameeting.business.GetFeedDelegate"></property>
- </object>
- <!--FrontControler-->
- <object id="appAwareCmdFactory" class="com.riameeting.factories.ApplicationModelAwareCommandFactory">
- <property name="applicationModel" ref="appModelInstance"/>
- <method-invocation name="addBusinessDelegateFactory">
- <arg>
- <ref>businessDelegateFactory</ref>
- </arg>
- <arg>
- <array>
- <value type="Class">com.riameeting.command.GetFeedCommand</value>
- </array>
- </arg>
- </method-invocation>
- </object>
- <object id="frontController" class="org.springextensions.actionscript.cairngorm.control.CairngormFrontController">
- <constructor-arg>
- <object>
- <property name="getFeedEvent" value="GetFeedCommand"/>
- </object>
- </constructor-arg>
- <constructor-arg value="com.riameeting.command"/>
- <method-invocation name="addCommandFactory">
- <arg><ref>appAwareCmdFactory</ref></arg>
- </method-invocation>
- </object>
- </objects>
Spring ActionScript入门教程(3)-Spring和Cairngorm的结合使用[下]2
可以看到主体配置分为4个部分:
- ModelLocator - 对应在Lib中创建的ApplicationModel,在此创建一个Model的实例
- Service Locator - 先创建一个ID为“feedService”的HTTPService,然后创建一个ID为“serviceLocator”的Service Locator,将feedService引入进去
- Delegate Factory - 我们通过配置代理工厂,将第二部分的服务注入到代理中去,这样代理就具备了通过自身调用服务的能力,而不需要同外部服务产生直接的依赖
- FrontControler - 首先我们配置工厂类ApplicationModelAwareCommandFactory,将Model注入到Command中去。然后创建一个前端控制器“frontController”,将事件与命令之间建立映射。
然后我们来创建一个关于视图的配置文件,定义界面上都显示什么样的组件,在view下面创建一个XML文件,名为“global.xml”,然后输入下面的内容:
- <objects>
- <object id="searchForm" class="com.riameeting.view.AddressBar">
- <property name="model" ref="appModelInstance"/>
- <property name="x" value="10"/>
- <property name="y" value="10"/>
- </object>
- <!--<object id="searchResult" class="com.riameeting.view.SearchResultWithTable">-->
- <object id="searchResult" class="com.riameeting.view.SearchResult">
- <property name="model" ref="appModelInstance"/>
- <property name="x" value="10"/>
- <property name="y" value="60"/>
- </object>
- <object class="com.riameeting.utils.ApplicationViewAssembler" init-method="init">
- <property name="elements">
- <value>
- <array>
- <ref>searchForm</ref>
- <ref>searchResult</ref>
- </array>
- </value>
- </property>
- </object>
- </objects>
你可以看到视图方面配置了三个部分,第一个对应我们在Lib中定义的搜索组件,ID是searchForm,第二个是用于显示Feed内容的列表组件,ID是searchResult,而第三个配置只是为了使用工具类将前两个组件添加到显示列表中。并且为每一个视图组件,都指定了Model的引用,就是我们在Cairngom.xml中配置好的Model。
然后我们定义一个主体的XML,在config下面创建一个名为“”的XML文件,引入上面创建的两个XML,内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <objects>
- <import file="view/global.xml"/>
- <import file="cairngorm/cairngorm.xml"/>
- </objects>
4.3 实现IoC容器载入
打开SpringActionScriptCairngormDemo.mxml,建立一个代码块,声明一下IoC容器,载入配置文件,代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" layout="absolute" width="420" height="480" viewSourceURL="srcview/index.html">
- <mx:Script>
- <![CDATA[
- import org.springextensions.actionscript.context.support.FlexXMLApplicationContext;
- private function init():void {
- var appContextPath:String = "config/application_context.xml";
- var context:FlexXMLApplicationContext = new FlexXMLApplicationContext(appContextPath);
- context.addEventListener(Event.COMPLETE,onIoCLoadComplete);
- context.load();
- }
- private function onIoCLoadComplete(e:Event):void {
- trace("loaded");
- }
- ]]>
- </mx:Script>
- </mx:Application>
编译并运行项目,就可以看到运行结果了。
演示地址:
http://www.riameeting.com/examples/SpringASCairngormDemo/SpringActionScriptCairngormDemo.html
提示:你可以在Demo上点击右键查看源码。
附件中是两个项目的源码下载。