|
列表C
<?xmlversion="1.0"encoding="UTF-8"?>
<beans> <beanid="user"class="tests.articlecode.coldspring.User"> <propertyname="utility"> <refbean="utility"/> </property> </bean>
<beanid="utility"class="tests.articlecode.coldspring.Utility"/>
<beanid="testFactory"class="tests.articlecode.coldspring.TestFactory"/> <beanid="test"factory-bean="testFactory"factory-method="getInstance"> <constructor-argname="parameters"> <map> <entrykey="user"> <refbean="user"/> </entry> </map> </constructor-arg> </bean> </beans>
上面的XML用到了多种不同的特性。首先要注意ColdSpring将多种组件识别为“beans”,这主要是源自于Spring的遗留物。有的时候我希望这个名字更加贴切一点,因为它们可能会使用者带来“bean”是什么的困惑。但是,如果您只把它们当成CFC,这就不会有任何问题。
第一个定义的bean是一个叫做User的CFC。它有一个叫做Utility的属性。如果接着这个定义往后看,您会看到第二个定义的是实用工具CFC。所以我们马上得出了结论,ColdSpring会:
- 启动一个Utility实例
- 启动一个User实例
- 由于我们告诉ColdSpring说User CFC要依赖Utility,所以ColdSpring会自动地寻找一个匹配被注入的bean的名字的setter方法(在这里是setUtility())。
- 最后,ColdSpring通过对User调用setUtility()方法把Utility注入到User里,同时把Utility实例作为一个自变量传递。这就叫做setter注入。
所以ColdSpring不仅会为您解决依赖性的问题,它甚至还能够自动地解决它们的排序问题。但是,从ColdSpring获得新的CFC还有其他的方式,见下面第三和第四个bean的定义。
上面列表C里的第三个定义定义了一个叫做TestFactory的CFC。正如您猜到的,这是一个工厂(Factory),也就是说,它的职责是创建其他的CFC。您可能会疑惑“为什么我们需要工厂?难道ColdSpring不已经是一个工厂了?”
是的,ColdSpring是一个工厂,但只是一个简单的工厂。通过允许我们从ColdSpring调用自定义的工厂,我们可以对已创建的CFC具有更大的控制权,让其具有更强的功能。只用想象一个简单的例子:我们想要一个ContactManager CFC,以便让服务器与系统管理员进行通信。在上班时间里,它可以创建一个处理电子邮件的CFC,但是在下班时间里,它会创建一个发送传呼信息或者文本短消息的CFC。向我们的工厂里添加一些额外的逻辑以便根据不同的情况实例化不同的CFC很容易。
正如您可以从最后一个bean的定义里看到的,我在使用TestFactory CFC,并让ColdSpring对它调用getInstance()方法。我还将一些数据直接传递给了工厂方法:一个带有User键的结构命名参数和一个我们先前创建的User CFC的值。
您可以使用这种叫做构造函数注入(constructor injection)的方式把依赖性直接注入到任何bean里,而不需要用先前讲到的setter注入方式。这两种方式都有各自的优点和缺点,但是setter注入的一个优势是您可以避免循环依赖性的问题。如果CFC1需要将CFC2作为构造函数自变量,但是CFC2也需要CFC1作为构造函数自变量,那么这就会出现循环依赖性的问题。
回到这个例子上,我们现在知道了ColdSpring将会根据我们定义的bean作出什么样的响应。现在我们可以开始使用它了。(列表D)
列表D
<cfset test = coldSpring.getBean('test') /> <cfoutput>date: #test.getDate()#</cfoutput>
总而言之,作为对调用getBean的响应,ColdSpring会:
- 启动一个Utility实例
- 启动一个User实例,把Utility注入到user.setUtility()里
- 启动一个TestFactory实例
- 调用testFactory.getInstance()并将一个数据结构作为自变量传递,后者会返回一个叫做Test的CFC。
好了,那现在又该怎么办呢?
上面所有这些都是人为的例子,为的是说明如何使用ColdSpring的一些功能。但是您可能会说,“我可以通过手动创建对象的方式自己做到这一切!”您当然可以。如果您不处理大量的CFC,像ColdSpring这样的框架的好处不会真正完全显现出来。
在上面这些例子里,管理几个CFC还不算很复杂的事情。管理200个CFC之间的依赖性就完全是另外一回事了。如果您以错误的顺序创建了CFC,那么它就会崩溃。如果忘记正确地传递一个CFC,那么它就会崩溃。ColdSpring可以为您完成这些工作。最后,ColdSpring的XML会为CFC依赖性制作一份优秀的图谱。您可以在XML文件的这个地方就看到所有的依赖性,而不是浏览众多的组件来试图弄清楚它们的依赖性。
大多数用于ColdFusion的流行MVC框架都通过插件或者适配器直接支持ColdSpring。很多甚至支持“自动连接(autowiring)”,这样当您在XML里定义了bean之后,插件会通过查找匹配bean名字的setter尝试向框架组件提供由ColdSpring生成的bean。Model-Glue、Mach-II和Fusebox都具备这种功能。
面向剖面的能力
除了依赖注入的能力,ColdSpring还向ColdFusion的用户引入了面向剖面编程(Aspect-Oriented Programming,AOP)的概念。AOP是解决特定类型问题的一种强大方式。AOP的一个常见用处是日志记录。您可能希望在某些方法被执行的时候写一个日志文件。在标准的面向对象编程(OO)方式里,您必须向用于处理日志记录的方法加入代码。
AOP改变了这种方式。您不需要在所有的地方都添加日志记录代码,而只用一次定义日志记录代码,然后AOP截取整个模型里的方法调用,并在方法调用的时候运行日志记录代码。
在实际操作中,ColdSpring会创建一个包装程序CFC(wrapper CFC),对原始的CFC进行扩展,并在调用这个CFC的时候把包装程序组件返回给您。您的代码甚至不知道它在处理包装程序而不是原始的组件;ColdSpring会透明地管理这些。它为所有原始CFC的方法都创建代理,但是允许您在代码执行之前和之后添加额外的代码(比如日志记录代码)。
Barney Boisvert有一个关于AOP代码的好例子,它会自动地在cftransaction块里装入您希望加入的任何方法调用。这使得您可以自动地添加或者删除对方法调用的数据库事务管理!您可以在他的博客里找到这段代码。
AOP能力的最后一个例子是RemoteFactoryBean。您可以通过使用AOP来接受任何模型组件,并为它生成一个远程的Façade组件。这可以让您将某些或者全部的方法向远程源开放,例如Web服务、AJAX或者Flash Remoting调用等。您甚至可以使用ColdSpring通过FlashUtilityService自动地将CFC数据转化成为ActionScript对象。
动手试试
我只能向您讲解ColdSpring主要特性的一些皮毛,但是我希望您能够知道它将很多强大的功能带到了您的面前。它是用于ColdFusion的依赖注入和AOP的实现,经过测试,性能稳定。您可以下载ColdSpring的示例代码,并阅读完整的文档。网上还有很多到CVS资源库的链接和关于这个话题的专用邮件列表。您自己动手试试就会体会到它的作用!
责任编辑:张琎
查看本文的国际来源 |