原文地址:http://blog.chinaunix.net/uid-122937-id-143055.html
配置和初始化 Parsley 框架通常包括以下步骤:
AS3 Metadata 标签可以用来配置像依赖注入或者消息等服务. 它们可以放到由 Parsley管理的任何类中去.使用 metadata 标签的配置可以与 XML 或者 MXML 的配置相结合. 几乎每个 metadata 标签每有与它相对应的 MXML 和 XML 配置标签. 为了避免冲突, MXML 和 XML 配置会优于 Metadata 配置, 因此你可以覆盖 metadata 配置而不必对类的代码进行修改.
每个 metadata 标签和它们的属性会在相应的章节的相关例子中说明:
这种配置只能被 Flex 程序使用. 其它的配置在 Flex 和 Flash 程序中都可用.
假定你要配置以下两个类:
package com.bookstore.service {
class LoginServiceImpl implements LoginService {
public var timeout:int;
public function login (username:String, password:String) : void {
// execute service
}
}
}
package com.bookstore.actions {
class LoginAction {
[Inject]
public var service:LoginService
[MessageHandler]
public function handleLoginEvent (event:LoginEvent) : void {
service.login(event.username, event.password);
}
}
}
你可以见到使用 metadata 已经配置了几个功能. 查看第4章依赖注入和第5章消息系统了解这些功能的细节.
MXML 配置文件
我们需要告诉容器管理这些类并创建以下 MXML file:
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:services="com.bookstore.services.*"
xmlns:actions="com.bookstore.actions.*">
<services:LoginServiceImpl timeout="3000"/>
<actions:LoginAction/>
</mx:Object>
请注意我们并不需要导入 Parsley . 只需要在 MXML 中添加普通的 object 标签. 除了 metadata 标签你还可以使用 MXML 标签进行其它配置 , 比如上面例子的 timeout 值.
框架的初始化
最后你需要初始化容器. 假设你将配置保存在 BookstoreConfig.mxml, 你可以使用以下命令将它初始化:
FlexContextBuilder.build(BookStoreConfig);
在许多程序中,以上的一行代码便是你唯一直接使用的 Parsley API.你可以在某些类的方法上添加 [PostConstruct] 标签让程序开始时执行这些方法. 查看第6.5章Context 周期了解细节.
理论上你也可以使用 Parsley 的 API:
var context:Context = FlexContextBuilder.build(BookStoreConfig);
var initializer:BookStoreInitializer = context.getObjectByType(BookStoreInitializer) as BookStoreInitializer;
initializer.execute();
但这种用法并不推荐使用. 在一般的程序中都无需直接使用 Parsley 的 API. 只有在 Parsley 基础创建你自己的框架时才使用.
使用 Parsleys MXML 标签
以上的 MXML 配置还可以使用 Parsley 标签来代替 object 标签:
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="http://www.spicefactory.org/parsley">
<mx:Script>
<![CDATA[
import com.bookstore.services.*;
import com.bookstore.actions.*;
]]>
</mx:Script>
<Object type="{LoginServiceImpl}">
<Property name="timeout" value="3000"/>
</Object>
<Object type="{LoginAction}"/>
</mx:Object>
使用这些特殊的标签比普通的标签有其它的功能. 两种方式都有优缺点:
普通 MXML 标签的优点:
Parsley MXML 标签的优点:
<Object lazy="true" type="..."/>
) ,也就是说在你第一次使用该对象之前它不会被初始化和配置.<Object singleton="false" type="..."/>
). 也就是说,每次从容器取这个对象或者将这个对象注入其它对象时,容器都会创建一个新的实例.在以下情况中,外部 XML 文件是 MXML 之外的另一个合适的选择:
当然你也可以在某部分配置中使用 XML 文件而仍然使用 MXML 配置来注入你的核心服务. 查看第3.5章将多个配置机制整合了解细节.
上面例子的 MXML 配置也可以配置成以下的 XML 配置:
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd"
>
<object type="com.bookstore.services.LoginServiceImpl">
<property name="timeout" value="3000"/>
</object>
<object type="com.bookstore.services.LoginServiceImpl"/>
</objects>
一般的 XML 配置跟使用 Parsley MXML 标签的 MXML 配置非常类似. 在底层它们实现的作用是一样的.唯一的不同是 XML 配置需要使用 XML 规范,标签不可以大写并且属性名需要使用-,如: targetProperty 要写成target-property .
假定你的配置文件是config.xml
,初始化还是使用一行代码:
XmlContextBuilder.build("config.xml");
编译在 XML 中配置的类
你需要注意的是:与在 MXML 中配置的类不同,XML 中配置的某些类如果没有被使用的话,它不会被编译到你的 SWC 或者 SWF 文件.
解决这个问题有三种方法(即:你想要把没有使用的类也要编译到 SWC 或者 SWF 文件):
compc
你可以将整个源代码文件夹包含到 SWC 文件) 然后使用mxmlc
编译器中的-include-libraries
选项将整个 SWC 包含到你的 SWF 文件.mxmlc
编译器的-includes
选项来包含某些类.如果你只认识 Flex IOC 容器的话,你可能不熟悉这种方式. 它跟 Java 的 Spring 框架中的 JavaConfig 有点相似. 它允许你使用代码的方式来创建要给 Parsley 管理的对象. 我们使用之前例子的那两个类并将它们添加到 IOC 容器中:
package com.bookstore.config {
class BookStoreConfig {
public const action:LoginAction = new LoginAction();
public function get service () : LoginServiceImpl {
var service:LoginServiceImpl = new LoginServiceImpl();
service.timeout = 3000;
return service;
}
}
}
我们使用了 ActionScript 来设置 timeout 属性. 无论你使用var
,const
或者一个 getter 函数来声明对象,这些对象都会被添加到 IOC 容器中.
初始化还是只用一行代码:
ActionScriptContextBuilder.build(BookStoreConfig);
这个配置模式允许你增加 metadata 标签:
[ObjectDefinition(singleton="false")]
public function get service () : LoginServiceImpl {
var service:LoginServiceImpl = new LoginServiceImpl();
service.timeout = 3000;
return service;
}
在上面的例子中,每次这个对象被请求时,容器都会调用 getter 函数. 默认的 singleton 属性是true
, 所以如果没有 metadata 标签的话 Parsley 只调用这个方法一次并把这个实例缓存起来,对于所有的注入都是重复使用同一个实例.
自Version2.2后,配置管理机制允许指定实例在运行期间,作为容器的一部分:
<parsley:ContextBuilder>
<parsley:FlexConfig type="{ServiceConfig}"/>
<parsley:FlexConfig type="{ControllerConfig}"/>
<parsley:XmlConfig file="logging.xml"/>
<parsley:RuntimeConfig instances="{[instance1, instance2]}"/>
</parsley:ContextBuilder>
如果你需要指定ID,也可标注子标签:
<parsley:ContextBuilder>
<parsley:FlexConfig type="{ServiceConfig}"/>
<parsley:FlexConfig type="{ControllerConfig}"/>
<parsley:XmlConfig file="logging.xml"/>
<parsley:RuntimeConfig>
<parsley:Instance id="obj1" instance="{instance1}"/> <parsley:Instance id="obj2" instance="{instance2}"/> <parsley:Instance id="obj3" instance="{instance3}"/>
</parsley:RuntimeConfig>
</parsley:ContextBuilder>
在RuntimeConfig标签中添加的对象与之后添加的DynamicObjects不同之处在于,前面的作为根对象,可注入到其它对象中,因为它们在上下文构建时已指定。
你甚至可以使用普通的<Object>为内部标签
<parsley:ContextBuilder>
<parsley:FlexConfig type="{ServiceConfig}"/>
<parsley:FlexConfig type="{ControllerConfig}"/>
<parsley:XmlConfig file="logging.xml"/>
<parsley:RuntimeConfig>
<parsley:Instance id="obj1" instance="{instance1}"/>
<parsley:Instance id="obj2" instance="{instance2}"/>
<parsley:Object id="obj3" type="{LoginInterceptor}"/> <parsley:MessageInterceptor method="intercept" type="{LoginEvent}"/> </parsley:Object>
</parsley:RuntimeConfig>
</parsley:ContextBuilder>
你也可以用编码方式进行配置:
var rcp:RuntimeConfigurationProcessor = new RuntimeConfigurationProcessor();
rcp.addInstance(instance1, "id1");
rcp.addInstance(instance2, "id2");
rcp.addClass(MyClass, "id3");
var builder:CompositeContextBuilder = new DefaultCompositeContextBuilder(viewRoot);
FlexContextBuilder.merge(MainConfig, builder);
builder.addProcessor(rcp);
builder.build();
虽然你可能在大多数程序中偏好于只用一个配置, 你不必一定要这样做. 你可以将本章所讲的配置进行组合使用.
对于一种配置,你也可以将它分成几个文件. 然后使用buildAll
方法:
FlexContextBuilder.buildAll([BookStoreServices, BookStoreActions]);
XmlContextBuilder.buildAll(["services.xml", "actions.xml"]);
ActionScriptContextBuilder.buildAll([BookStoreServices, BookStoreActions]);
你也可以使用CompositeContextBuilder
类将它们合并在一起:
var builder:CompositeContextBuilder = new CompositeContextBuilder();
FlexContextBuilder.merge(BookStoreConfig, builder);
XmlContextBuilder.merge("logging.xml", builder);
builder.build();
这种方式也是很简单的: 你只需创建一个CompisiteContextBuilder
类的实例并把它放到各个context builder 类的merge
方法中.
以上所有的例子最终的结果都是一个 Parsley Context. 无论你有多少个配置文件,结果都是一样的.
对于大型和复杂的程序,你想要创建模块化 Contexts, 即多个配置不是合并到一个 Context, 以便它们可以根据需要进行加载和缷载. 对于模块化的程序你可以阅读第8章使用 Flex Modules和第6.4章Modular Contexts.
最后,如果你想要创建你自己的配置模式并将它与现有的配置方式无缝地结合的话, 你可以创建ObjectDefinitionBuilder
接口的实例并将它们传入到CompositeContextBuilder.addBuilder
. 查看第11章扩展本框架了解细节 .