转载:http://blog.sina.com.cn/s/blog_545edcb00100at2k.html
w3wp.exe 频繁重启 (Faulting application w3wp.exe) Faulting application w3wp.exe, version 6.0.3790.3959, stamp 45d6968e, faulting module kernel32.dll, version 5.2.3790.3959, stamp 45d742c2, Debug? 0, fault address 0x0000bee7. 中文搜索没有找到解决办法。英文搜索也没有找到解决办法。最后自己还是只能靠自己。原因在于,IIS的应用程序池主动回收w3wp.exe进程,就会使其 崩掉。这应该是微软的一个BUG。解决办法非常简单,打开应用程序池的属性页,在“回收”选项卡把所有的复选框去掉,让.NET的垃圾回收来管理内存而不 要让IIS来插手。
[Memcached]Windows下的.NET+ Memcached安装
转载请标明出处: http://www.yaosansi.com
原文:http://www.yaosansi.com/post/1396.html
Memcached官方:http://danga.com/memcached/
关于Memcached的介绍请参考:Memcached深度分析
下载Windows的Server端
下载地址:http://code.jellycan.com/memcached/
安装Memcache Server(也可以不安装直接启动)
1. 下载memcached的windows稳定版,解压放某个盘下面,比如在c:\memcached
2. 在CMD下输入 "c:\memcached\memcached.exe -d install" 安装.
3. 再输入:"c:\memcached\memcached.exe -d start" 启动。NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。这样服务器端已经安装完毕了。
如果下载的是二进制的版本,直接运行就可以了,可以加上参数来加以设置。
常用设置:
-p <num> 监听的端口
-l <ip_addr> 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u <username> 以<username>的身份运行 (仅在以root运行的时候有效)
-m <num> 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c <num> 最大同时连接数,默认是1024
-f <factor> 块大小增长因子,默认是1.25
-n <bytes> 最小分配空间,key+value+flags默认是48
-h 显示帮助
然后就可以用.net 的memcached客户端来试一下了。
C# 下可用的API(每个客户端API中都有详细的说明和注释)
https://sourceforge.net/projects/memcacheddotnet/
http://www.codeplex.com/EnyimMemcached/ – Client developed in .NET 2.0 keeping performance and extensibility in
mind. (Supports consistent hashing.)
http://code.google.com/p/beitmemcached/ – Client developed by BeIT with many new features.
[Java]Eclipse 3.6 M2发布
转载:http://www.javaeye.com/news/10443
Eclipse 3.6 M2发布。
下载Eclipse 3.6 M2:http://download.eclipse.org/eclipse/downloads/drops/S-3.6M2-200909170100/index.php
也可以使用p2来更新:
http://download.eclipse.org/eclipse/updates/3.6milestones
新功能介绍:
http://download.eclipse.org/eclipse/downloads/drops/S-3.6M2-200909170100/eclipse-news-M2.html
新版本添加了新的功能,比如API 使用浏览:
[MVC]适合ASP.NET MVC的视图片断缓存方式(下):页面输出原则
转载:http://www.cnblogs.com/JeffreyZhao/archive/2009/09/22/aspnet-mvc-fragment-cache-3-rendering-principle.html
上一篇文章里已经把Html.Cache打造成了非常具有可用性的API,需要缓存时我们只需在页面上做一个标记即可:
<% Html.Cache("cache_key", DateTime.Now.AddSeconds(10), () => { %> <% foreach (var article in Model.Articles) { %> <p><%= article.Body %></p> <% } %> <% }); %>
标记内部的写法和普通视图的写法相同,您可以for/foreach/if,也可以<%= %>,或者使用RenderPartial等其他辅助方法输出内容,都会被一并缓存下来。只可惜,上次文章末尾我提到有些效果是有前提的。
这个前提就是:某些RenderPartial和其他一些辅助方法的实现需要进行修改。好吧,再说的直接一些:如果您使用标准的ASP.NET MVC,就无法使用RenderPartial的功能。我认为造成这种问题的原因是ASP.NET MVC框架在实现时没有遵守页面内容输出的准则。所以我建议您使用MvcPatch项目进行ASP.NET MVC开发。
不过现在,我们还是来讨论一下准则吧。下面有些内容涉及到ASP.NET WebForm页面的输出方式,如果您遇到了不理解的地方,可以去看一下这篇文章,它是我为“页面片段缓存”原理介绍而写的“铺垫”。
在普通情况下,一个ASP.NET页面输出时是向一个封装了Response.Output的HtmlTextWriter中写入内容的:
而我们的片段缓存实现为了“捕获”某个缓存块输出的内容,则在HtmlTextWriter与Response.Output之间又插入了一个RecordWriter:
那么,在缓存命中的时候,我们的Cache方法把缓存中的内容写到什么地方去了呢?
public static void Cache( this HtmlHelper htmlHelper, ...) { var content = ... if (content == null) { ... } else { htmlHelper.Output.Write(content); } }
Output是什么?如果您观察ASP.NET MVC的源代码,您会发现HtmlHelper并没有这个属性。这是我在MvcPatch中暴露出来的一个TextWriter,它便是当前正用于页面输 出的HtmlTextWriter对象。因此,我这里提出一个原则:如果您是在向页面输出内容,请务必将所有内容通过页面的Writer输出。
在原来的ASP.NET MVC实现中,由于无法从HtmlHelper中获得页面的Writer,因此如果需要输出内容,则只能通过Response.Write方法,或由 Response.Output输出内容了。根据上图可知,如果我们直接从Response.Output输出,那么这部分内容是无法被 RecordWriter捕获的。这意味着什么呢?这意味着,如果我们上面不是通过HtmlHelper.Output,而是直接向 Response.Output输出,在Html.Cache嵌套的情况下,内层缓存块的输出无法被外层缓存块捕获到。因此,如果内层缓存命中,而外层重 新生成内容,则会发现内层缓存块的内容被没有被外层记录下来。
我们可以想的再远一些。我们这种TextWriter的嵌套其实是一种什么模式呢?应该算是装饰器模式吧。 装饰器模式要求我们所有的输出都从链条的顶部输入,这样所有的“装饰”作用才会生效。如果我们获取了其中的某一个环节,直接从这个环节输入参数,那么自然 是失败的。这意味着……假如又有另外一个组件在“行使”它的扩展权力呢?如果又有另一个组件,它在我们的RecordWriter外层又进行了包装呢?我 们的片断缓存解决方案是一种扩展,作为扩展方案,不应该破坏其他组件正常扩展的能力。因此,我们需要从页面的Writer中输出内容。
一个很好的反例就是ASP.NET MVC框架,您看RenderPartial方法的输出目标是什么:Response.Output。还有FormExtensions及MvcForm 对象的输出目标是什么:还是Response.Output。这意味着,ASP.NET MVC框架的做法直接破坏了视图的扩展能力。也直接放倒了我们的片断缓存实现。因此,我最终构建了MvcPatch项目,因为在这一点上(以及其他一些方 面,之前也有所提及)使用扩展的方式实在是无法进行修补的。
所以国外社区有种调侃称,微软产品是好的,但是他们自己不知道该如何用好自己的产品。例如我一直说的WebForms的滥用,还有这里ASP.NET MVC实现。前者更像是一种商业策略,而后者可能……就令人摸不着头脑了。
我没有说“微软的确不知道如何用好自己的产品”。因为从ASP.NET MVC的代码中可以发现,好像他们并非不知道我刚提出的页面输出原则。证据在于,他们已经在ViewPage中留有一个“入口”了:
public class ViewPage : Page, IViewDataContainer ... public HtmlTextWriter Writer { get; private set; } protected override void Render(HtmlTextWriter writer) { Writer = writer; try { base.Render(writer); } finally { Writer = null; } } }
看看这段代码在做什么?这段代码重写了Render方法,将外部传入的HtmlTextWriter对象保留了起来!这意味着 ViewPage.Writer属性获得的便是当前正在输出的HtmlTextWriter对象!也就是说,ASP.NET MVC似乎在建议您说,如果您非要在页面上使用Response.Output输出的话,现在就改成Writer的输出吧:
<% Response.Write("Hello World");%><% Writer.Write("Hello World"); %>
不知道是可惜还是可笑,如果您在代码中对Writer属性使用Find All References,您会发现除了在ViewMasterPage或ViewUserControl中继续暴露Writer属性之外,就再也没有使用过 了……那么RenderPartial在做什么?FormExtensions在做什么?谁知道……我同样不知道的是,如果微软自己没有这个“意识”,那 么又为什么要主动保留Render时的Writer呢?
不管这些了。我们最后总结一下:
- 如果您在使用WebForm模型,请像ViewPage那样保留当前Writer,并且向Writer内输出,不要搞Response.Write/Output。
- 如果您在编写视图的辅助方法,请向HtmlHelper.Output输出,而不是Reponse.Write/Output。
- 如果您发现其他项目在使用Response.Write/Output,请将它修改成页面的Writer输出。
- ……
嗯?您说HtmlHelper没有Output属性?没关系,下载代码以后自己修改编译一下,或直接使用MvcPatch吧。
[Flex]Adobe Flash Catalyst 最佳实践
转载:http://www.riameeting.com/node/444
这是一篇来自Adobe开发者中心的文章,原文链接:http://www.adobe.com/devnet/flashcatalyst/articles/flash_catalyst_best_practices.html
Adobe Flash Catalyst 是个新的专业交互设计工具,使用它,您可以不用写代码,快速的创建应用程序接口,和交互内容。
通常,我们使用Flash Catalyst时,你会觉得工作在整个开发团队的边缘,并且很难将你的Flash Catalyst项目文件与团队的其他成员分享,以便于他们可以继续开发这个项目,或者使用其中你定义的的组件皮肤。
越接近你使用Illustrator设计和构建的艺术原创稿,你的FC项目就越具备冲击力,随之而来的,这种冲击力将会延续到资源和皮肤的质量和有效性上,使得开发者使用这些资源变为可能。
在这篇文章中,我将会提供一些示意和提示以便于你可以更容易地结构化地将设计的资源从Illustrator里移动到 Flash Catalyst里。 我同样会强调一些Flash Catalyst的最佳实践,这将会确保你可以用最少的重构时间来让你的资源可以继续在Flash Builder里开发。
使用Illustrator
注意:这篇文章主要集中在使用Adobe Illustrator做艺术设计之后为Flash Catalyst使用上。 你也可以使用Adobe Photoshop或者Adobe Fireworks来做设计和创作;下面很多提示和说明在这些工具中同样是适用的,虽然我不准备在这里介绍他们的使用方法。
设计好你的Illustrator文件结构
你可以整理好你的Illustrator文件结构,这样可以使应用程序中不同的功能模块区域和用户界面被定义在分开的层和子层中(见图1)。
图1 Illustrator 中的层面板(左)和Flash Catalyst中的层面板(右)。
你可以通过在你在Illustrator中指定逻辑结构和有意义的名字,使在Illustrator 中定义的层,子层,和组在Flash Catalyst中同样有效;在使用Flash Catalyst工作的时候你将会明白这个文件结构的用途。 这很重要,你需要在转换设计稿到组件时选定层和组,以及程序中不同功能区间之间的转换动画。
在单个画板上进行设计
Flash Catalyst不支持多画板设计,所以,比起在不同的画板上表现不同的功能区间和用户界面,使用一个单独的画板,但将不同的区间分布到不同的层里面,会比较好(见图2)。
图2 在Illustrator项目中的层面板定义了一个程序中的五个功能区间,例如背景层和前景层。
在图2中,背景图和前景在程序中保持一致(并且总是显示),每一个其他的顶级层表现了用户可以看到的不同的程序功能区间。
为每个部分都命名
就像给层和组命名一样,为Illustrator 文件中的每个独立图形和元素命名也是很重要的。 你也许会考虑在整个文件中使用共用命名策略,比如用“Button_name”来指定这些图形元件将会在随后转换成元件时,被转换成按 钮,“Text_name”“TextInput_name”“Custom_name”,以此类推。
元素的命名并非一个正式的规范,但是使用命名策略会得到整个互动开发项目中的设计师和工程师的认可,这样会让所有人都知道如何在程序中使用这些组件,从而避免之后可能发生的混乱和返工。
不要链接外部的图片文件
在团队环境中,你很可能需要将你的Illustrator文件交付给一个使用Flash Catalyst工作的互动设计师;不要在Illustrator中链接外部文件,取而代之的是将它们置于Illustrator文件内部,这样你可以通 过单个的文件做转换,并确保随后的设计师能在项目的随后工作中使用全部的资源。 Illustrator 中的图片和其他资源将会显示在Flash Catalyst中的Library面板中。
在你将图片导入进Illustrator之后,你要确定你执行了Object > Rasterize 选项来改善图片的显示效果。 在这个对话框中,为界面浏览选择72 DPI 、typically,你需要将背景设置为透明。
标记副本组件和资源的
在Illustrator中通常需要提取出多态的,重复的按钮,输入文本框,和其他的可视元素,以便于描绘整个程序界面的全景图形设计。 在Flash Catalyst中,你需要为每个美术设计定义一个单独的组件,但是,当是同样的设计的时候,就要避免定义多个组件。
比起来依赖于不重复的元件来做判断,不如考虑在Illustrator文件里为元件标记一个副本,这样你就可以很清楚的知道他们是不需要被重新定义的。
你可以考虑使用一个命名策略,例如用主设计上用“TextInput_Blue”标记这个组件,用“_textInput_Blue”来表示一个副 本。 或者你也可以选择将所有副本组件的alpha值设置为40%(见图3);这从视觉上表示这个组件不需要被重定义,你可以在Flash Catalyst里用一个库中的实例来置换它。
图3 上方的输入文本框定义了一个在Flash Catalyst中的组件。
使用“create outlines”来为文本添加滤镜和效果
虽然,Flash Catalyst在支持Illustrator文件格式方面做的很出色,但是你会发现,文本的滤镜和效果并没有像你预期的那样被渲染出来。如图4所示。
图4. 原始设计(左)和在导入到Flash Catalyst之后的效果(右)。
在这个例子里,你可以在Illustrator 使用“create outlines”选项解决这个问题,并为文本创建一个矢量的表现。 不过,这意味着,这个文本将变成不可编辑的了。
你可以将这种方法使用在那些你不准备绑定到你程序中的,较小数量的静态文本上,例如,标题,商标等等。
不要在Illustrator中定义所有组件区域
虽然你可以在Illustrator中定义所有的组件,但这没有什么意义,因为Flash Catalyst中同样提供了比较的全面的选项用于编辑文本和图形元件的属性,包括填充,渐变,和描边(见图5).
图5 即将面世版本的Flash Catalyst中的属性面板。
你会因此发现在Illustrator 设计原稿和随后都可以很方便的做调整,一旦你将一个组件导入到Flash Catalyst中,就可以使用states面板来设置调整每一个区域的可见属性。
为数据列表组件定义一个单独的元素
当将原稿转换为Flash Catalyst中的数据列表组件时,你只需要指定一个单独的重复使用的列表选项。 如果你需要在Illustrator的用户界面中绘制出数据列表的全貌,你可以选择定义两种截然不同的区域:使用在Flash Catalyst中的独立版本,和一个包含了其余项的分散的组。(见图6)
图6. 为数据列表设计的填充项,下面的组表现出这个列表在Illustrator中看起来的样子。
这种方法可以利用组来排列和分隔这些选项在数据列表中的样子,但是最后在随后的开发中将他们移除。
Flash Catalyst
下面的一些点,是讲如何使用Flash Catalyst和你的团队一起工作了。
在基本规范上使用“Save as copy”
当你在Flash Catalyst中使用不同的方式进行过实验,并学习如何更好的使用这个新工具,你会发现使用“Save as copy”选项对频繁的使用是很有价值的。 在着手构建你的主项目结构时,这显得尤为重要,例如对组和层次做重大调整时,或者添加新的功能区间和定义过渡方式时。
如果有什么东西是不能在计划中完全确定的,你可以很快捷的恢复到之前这个文档保存的版本,然后尝试其他方式。
按照正确的顺序进行工作
当你把一个静态的设计原稿从Illustrator文件中导入进一个Flash Catalyst中的动态的富媒体网络应用时,按照正确的逻辑顺序开始工作就变得非常重要了。 你会喜欢这种方式,并在你以往的工作经验基础上适应它的。
- 将所有设计原稿中的东西转换为组件。(使用层面板中的 显示/隐藏 功能,显示程序在某个特定时间程序界面应该显示的东西。)
- 创建一个自定义的,或者通用的组件,来定义一个程序的功能小模块(例如,为程序界面的表单创建一个自定义的组件,或者一个独立的窗口)
- 这个组在功能区域里面下的可见元件被引入到逻辑集合中;这在定义场景过渡时会显得特别有用,你可以成组的设置元素的属性,而不必一个个的去单独设置。(见图8)
- 使用自定义的组件和定义在组件上交互效果来创建过渡动画,将会带来组件区间的变化。
- 在某个时间点创建一个状态,对于每一个状态要注意以下几点:
- 定义组件的位置,可见性,和出现效果。
- 使用时间线来指定新的状态和之前的状态之间的过渡。
- 在一个状态下定义元件的交互行为,这些行为将会触发程序状态的切换
图7 这个表单在 Flash Catalyst中将被转化成一个自定义,或者通用的组件。
图8. 成组的元素,使得通过时间线来操作他们变得更加容易。
使用优化过的图形
从Illustrator中导入过于复杂的矢量图形是一种不必要的开销,而且在Flash Player里渲染这些图形也会造成程序的性能问题。 如果在你的程序界面中,有这样的图形,并不需要运行时在其上做任何相应的改变,那么你可以在Flash Catalyst中使用转换为优化图形选项(见图9)。
图9 在复杂的矢量图形上使用转换为优化图形选项。
如果你想要矢量图形在被导入进Flash Catalyst中时自动被优化转换,你应该在Illustrator的原稿中将其定义为符号。
考虑组件的重用性
当在Flash Catalyst中做组件转换时,通常要为在Illustrator中定义的文本指定尺寸,例如按钮,单选框,和复选框。 如果你计划在别处重复使用这些组件,请确保在组件中延长文本框的尺寸以适应其他标签。(见图10)
图10 调整单选按钮中的文本以适应组件。
定义有意义的状态名称
你在 Flash Catalyst中定义的状态名称,同样被使用在输出的程序代码中,这对于前端的开发团队是相当有价值的,因为这个名字说明了它应该被定义成怎样的组件。(图11)
图11 在Flash Catalyst中使用 Pages/States 面板做状态命名。
在任何情况下,状态名称都应该清楚的诠释用户在程序中那一个功能点上需要处理的事情,正在浏览的页面,或者其他有意义的叙述。
在库中重命名组件
跟状态命名一样,在库中为组件命名是广泛应用在整个程序代码编写和项目构建过程中的。 考虑到与前端开发团队沟通的关系,指定统一的命名规范对从互动设计到开发的过渡很有帮助。(见图12)
图12 TextInputSm和TextInputMd显而易见的表示小码和中码的输入文本组件;而RepeatedItem1和RepeatedItem2表达的就不是那么的清楚了。
使用代码视图来做优化
不,你并不需要是一个资深的程序员,你只需要注意几件事情就可以了。
首先,你要鉴别所有文本框使用的字体都是标准的系统字体(例如Arial),或者是你已经绑定在程序中的字体。(这将会增加程序的体积) 如果你在一些地方使用了非标准的字体,例如,一个标志或一个标题,也许最好返回到Illustrator中把他们转换为图形。
其次,从Illustrator 中导入的资源,其冗长的代码段中包含精确的路径,渐变,描边,这些会使得资源更加生动,在Flash Catalyst里,这些也是可以被优化的。 检查包含代码的组的名称,然后在设计视图中,找到art board上的这个组,选择转化为优化图形。
记住,这个转变仅仅作用在单个状态下
当你在程序中和组件里做完了这个设计转化之后,如果你要你做的改动作用于所有状态,你需要通知Flash Catalyst,如果你不通知,那么这个改变将只会作用于当前的状态。 右键单击要改动的元素,选择“Make Same in All Other States”,在做完改变之后所有状态下的组件就都随之更改了(见图13);
图13 Make Same in All Other States选项确保任何修改都会被应用到所有的状态中。
在真实的浏览器环境中预览状态切换
虽然,你可以在Flash Catalyst中的时间轴上预览你定义的过渡动画,但将输出结果显示在参数真实的浏览器里无疑是最好的选择。(使用 File > Run Project 来做浏览)
从这里出发,我们还可以做什么
讨论Flash Catalyst和为Flash Catalyst的发展提出好的点子,请访问 Adobe Forums for Flash Catalyst 学习更多 Flash Catalyst知识,到Adobe Labs下载课件和教程。
获得公用许可。
这个工作是受到类似于3.0 Unported许可一样的非商用知识共享许可所认可的。
关于作者
Andrew Shorten是一个Adobe的平台技术传道士,并热衷于改良优化,丰富的基于电脑的用户体验。 Andrew在富士通,为政府,企业客户做过网站,报刊,以及移动设备的用户界面开发。 此后,他在Macromedia,Microsoft和Adobe工作,期间,他作为设计师,开发工程师,网站代理和组织帮助他们实现丰富的,动人和成功 的网站以及左面应用程序。
翻译:RIAMeeting翻译小组 王贺
[Flex]Spring ActionScript入门教程(3)下
转载:http://www.riameeting.com/node/451
本文接上一部分继续完成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>
可以看到主体配置分为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 context:FlexXMLApplicationContext = new FlexXMLApplicationContext(appContextPath); context.load(); } trace("loaded"); } ]]> </mx:Script> </mx:Application>
编译并运行项目,就可以看到运行结果了。
演示地址:
http://www.riameeting.com/examples/SpringASCairngormDemo/SpringActionScriptCairngormDemo.html
提示:你可以在Demo上点击右键查看源码。
附件中是两个项目的源码下载。
[Flex]Spring ActionScript入门教程(3)
转载:http://www.riameeting.com/node/451
本文接上一部分继续完成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>
可以看到主体配置分为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 context:FlexXMLApplicationContext = new FlexXMLApplicationContext(appContextPath); context.load(); } trace("loaded"); } ]]> </mx:Script> </mx:Application>
编译并运行项目,就可以看到运行结果了。
演示地址:
http://www.riameeting.com/examples/SpringASCairngormDemo/SpringActionScriptCairngormDemo.html
提示:你可以在Demo上点击右键查看源码。
附件中是两个项目的源码下载。
[Flex]Spring ActionScript入门教程(2)-一个简单的实例
转载:http://www.riameeting.com/node/449
在这个部分,我们来使用前一章学到的知识,建立一个简单的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 { context = new FlexXMLApplicationContext(appContextPath);//创建一个IoC容器 context.load();//加载配置文件 } addChild(context.getObject("container"));//加载配置结束后,将 container容器(即Panel)添加到显示列表 } ]]> </mx:Script> </mx:Application>
按下F11键,调试项目,怎么样,是否看到一个显示数据的列表了?
好了,到这里一个简单的Spring ActionScript的例子就完成了,我们将在下一个章节中深入探讨如何结合Cairngorm,这样才能适应一个大型项目的开发流程。
附件中是本实例的源码。
[Flex]Spring ActionScript入门教程(1)-简介
转载:http://www.riameeting.com/node/448
这是一个系列文章,总共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
Part 3: 使用Spring ActionScript中的XML配置
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> </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} |
|
Part 4: 使用容器载入配置文件
上面我们讨论如何编写一个配置文件,然后我们看一下如何在Flex中载入并解析这个文件。
首先需要了解的是,我们如果要在Flex中使用DI注入对象,需要使用一个IoC容器来做这件事。 FlexXMLApplicationContext 或 XMLApplicationContext 是Spring关于IoC的基础容器。两者基本相同,第一个只是增加了对Flex的支持,比如ArrayCollection。一般也认为这是程序的入 口,我们写代码的开始会用到这两个类,用于载入和分析配置文件(XML)。
使用容器载入配置的代码示例:
var applicationContext:XMLApplicationContext = new XMLApplicationContext(); applicationContext.addConfigLocation("application-context.xml"); applicationContext.load();
在下一个章节,我们将来讲述使用Spring ActionScript创建一个简单的实例,而在第三个章节,我们则会引入Cairngorm。
[MVC]适合ASP.NET MVC的视图片断缓存方式(中):更实用的API
转载:http://www.cnblogs.com/JeffreyZhao/archive/2009/09/21/aspnet-mvc-fragment-cache-2-more-friendly-api.html
上一篇文章中我 们提出了了片断缓存的基本方式,也就是构建HtmlHelper的扩展方法Cache,接受一个用于生成字符串的委托对象。在缓存命中时,则直接返回缓存 中的字符串片断,否则则使用委托生成的内容。因此,缓存命中时委托的开销便节省了下来。不过这个方法并不实用,如果您要缓存大片的HTML,还需要准备一 个Partial View,再用它来生成网页片段:
<%= Html.Cache(..., () => Html.Partial("MyPartialViewToCache")) %>
但是在实际开发过程中,我们最乐于看到的使用方法,应该只是使用某个标记来“围绕”一段现有的代码。也就是说,我们希望的API使用方式可能是这样的:
<% Html.Cache("cache_key", DateTime.Now.AddSeconds(10), () => { %> <% foreach (var article in Model.Articles) { %> <p><%= article.Body %></p> <% } %> <% }); %>
我们可以从这种“表现形式”上推断出这个Cache方法的签名:
public static void Cache( this HtmlHelper htmlHelper, string cacheKey, CacheDependency cacheDependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, Action action) { ... }
与前一个扩展相比,最后一个委托参数变成了Action,而不是Func<string>。这是因为ASP.NET页面在编译时,会将页面Cache块中的代码,编译为内容的输出方式——这点在之前的文章中已经有过比较详细的描述。不过有一点还是与之前相同的,我们要省下的是action委托的开销。也就是说,如果缓存命中,则不执行action。缓存没有命中,则执行action,获得action生成的字符串,加入缓存并输出。
看似比较简单,但这里有个问题:如之前的Func<string>参数,我们执行后自然可以获得一个字符串作为结果。但是现在是个action,执行后它又把内容输出到什么地方去,我们又该如何得到这里生成的字符串呢?根据页面输出行为,我们可以推断出页面上的内容是被写入一个HtmlTextWriter中的。那么,这个HtmlTextWriter又是如何生成的呢?
它是根据Page类型的CreateHtmlTextWriter方法生成的:
protected virtual HtmlTextWriter CreateHtmlTextWriter(System.IO.TextWriter tw) { ... }
在页面准备生成内容之前,Page会调用其CreateHtmlTextWriter来包装一个TextWriter,这个 TextWriter一般即是由Response.Output暴露出来的HttpWriter对象。CreateHtmlTextWriter方法生成 的HtmlTextWriter,便会交给Page的Render方法用于输出页面内容了。这便是我们的入手点,我们可以趁此机会在 HtmlTextWriter和CreateHtmlTextWriter之间“插入”一个组件。这个组件除了将外部传入的数据传入内部的 TextWriter以外,还有着“纪录”内容的功能:
internal class RecordWriter : TextWriter { public RecordWriter(TextWriter innerWriter) { this.m_innerWriter = innerWriter; } private TextWriter m_innerWriter; private List<StringBuilder> m_recorders = new List<StringBuilder>(); public override Encoding Encoding { get { return this.m_innerWriter.Encoding; } } public override void Write(char value) { ... } public override void Write(string value) { if (value != null) { this.m_innerWriter.Write(value); if (this.m_recorders.Count > 0) { foreach (var recorder in this.m_recorders) { recorder.Append(value); } } } } public override void Write(char[] buffer, int index, int count) { ... } public void AddRecorder(StringBuilder recorder) { this.m_recorders.Add(recorder); } public void RemoveRecorder(StringBuilder recorder) { this.m_recorders.Remove(recorder); } }
一个TextWriter有数十个可以覆盖的成员,但是一般情况下我们只需覆盖其中三个Write方法就 可以了。以上代码用Write(string)作为示例,可以看出,如果RecordWriter中添加了Recorder之后,便会将外界写入的内容再 交给Recorder一次。换句话说,如果我们希望纪录页面上写入Writer的内容,只要在RecordWriter里添加Recorder就可以了。 当然,在此之前我们需要为视图页面“开启”缓存功能:
// 定义在CacheExtensions中 public static TextWriter CreateCacheWriter(this HtmlHelper htmlHelper, TextWriter writer) { var recordWriter = new RecordWriter(writer); htmlHelper.SetRecordWriter(recordWriter); return recordWriter; } // 定义在视图页面(aspx)中 <script runat="server"> protected override HtmlTextWriter CreateHtmlTextWriter(System.IO.TextWriter tw) { return base.CreateHtmlTextWriter(Html.CreateCacheWriter(tw)); } </script>
当然,在实际开发过程中不会再aspx中重写CreateHtmlTextWriter方法,我们往往会将其放在视图页面的共同基类中。例如在 我的项目中,我就为所有的视图“开启”了这种纪录功能。由于在没有缓存的情况下这层薄薄的封装只是在做一个“转发”功能,因此不会带来性能问题。
此时,新的Cache方法便非常直观了:
public static void Cache( this HtmlHelper htmlHelper, string cacheKey, CacheDependency cacheDependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, Action action) { var cache = htmlHelper.ViewContext.HttpContext.Cache; var content = cache.Get(cacheKey) as string; var writer = htmlHelper.GetRecordWriter(); if (content == null) { var recorder = new StringBuilder(); writer.AddRecorder(recorder); action(); writer.RemoveRecorder(recorder); content = recorder.ToString(); cache.Insert(cacheKey, content, cacheDependencies, absoluteExpiration, slidingExpiration); } else { htmlHelper.Output.Write(content); } }
如果缓存没有命中,则我们会向RecordWriter中添加一个Recorder,然后再执行action委托,这样action中的所有内容便会被纪录下来。action执行完毕后,我们再摘除Recorder即可。现在Cache方法已经可用了,例如:
<%= DateTime.Now %> <br /> <% Html.Cache("now", DateTime.Now.AddSeconds(5), () => { %> <%= DateTime.Now %> <% }); %>
那么,Html.Cache能否嵌套呢?答案也是肯定的。
<%= DateTime.Now %> <br /> <% Html.Cache("now", DateTime.Now.AddSeconds(5), () => { %> <%= DateTime.Now %> <br /> <% Html.Cache("inner_now", DateTime.Now.AddSeconds(10), () => { %> <% Html.RenderPartial("CurrentTime"); %> <% }); %> <% }); %>
外层缓存块5秒后过期,内存缓存块10秒钟过期,因此在某一时刻(如第一次刷新后7秒后),您会发现页面上会出现这样的结果:
2009/9/21 15:36:10 2009/9/21 15:36:08 2009/9/21 15:36:03
我们的RecordWriter支持同时拥有多个recorder,您可以根据上面得出的结果来理解内外层循环是以何种顺序向RecordWriter添加Recorder的,这并不困难。
从代码中我们也可以发现,Cache块内部也可以直接使用Html.RenderPartial。您也可以在Cache块内部使用各种辅助方法,它们的结果会被一并缓存下来。
不过它们还是有“前提”的,至于这个前提是什么,我们下次在讨论吧。如果您想先睹为快,可以关注MvcPatch项目。