将Tapestry整合到Spring里去
原文:http://tech.blogbus.com/logs/2004/04/139683.html
在Spring最新的文档里,有关于如何将Tapestry整合到Spring里去的说明,见这里http://www.springframework.org/docs/reference/view.html#view-tapestry。Spring中文论坛应该会翻译出来,我就不做重复的工作,只摘要说明一下。
先看看Tapestry。下图说明了Tapestry是怎么样获取到service的。
在文档里,基于Tapestry和Spring的应用被划分成五层,我们只关注前边两层:User Interface Layer和Service Layer。这种划分对于单独使用Tapestry的应用也是成立的,从上图可以看出,那是对Service Layer的操作。当进行整合之后,User Interface Layer仍然是由Tapestry提供,而Service Layer则由Spring接手来提供。
Service实际上就是Bean,Tapestry原本一套取得Service的机制:getEngine()->getService()。现在,我们用Spring将这些Serviec,也就是Bean管理起来,那么,要解决的问题就只有一个,如何让Tapestry获得由Spring管理起来的的Service?
在Application Context里我们定义了需要被调用的Bean(见文档),我们给它个名字就userService。那么,在Tapestry的page里,就需要载入这个context,然后取得beanA。
一个最简单的方法是利用Spring的static工具WebApplicationContext在Tapestry page对应的Java class definition里直接载入Application Context,并取得userService。
WebApplicationContext appContext = WebApplicationContextUtils.getApplicationContext( getRequestCycle().getRequestContext().getServlet().getServletContext()); UserService userService = appContext.getBean("userService");
|
不过这种用法和我们用Spring的原意有点违背——这不符合DI模式。应该在page里才决定我们调哪个Service。
所以,推荐的做法如下。
第一步,让Tapestry page能够获得ApplicationContext,但这次不直接由Tapestry page来做,因为在我们需要访问ApplicationContext的时候,Tapestry page很难拿到ServletContext,所以我们将其放到Enging里去做。代码如下:
package com.whatever.web.xportal; ... import ... ... public class MyEngine extends org.apache.tapestry.engine.BaseEngine { public static final String APPLICATION_CONTEXT_KEY = "appContext";
protected void setupForRequest(RequestContext context) { super.setupForRequest(context); // insert ApplicationContext in global, if not there Map global = (Map) getGlobal(); ApplicationContext ac = (ApplicationContext) global.get(APPLICATION_CONTEXT_KEY); if (ac == null) { ac = WebApplicationContextUtils.getWebApplicationContext( context.getServlet().getServletContext() ); global.put(APPLICATION_CONTEXT_KEY, ac); } } |
这样就把ApplicationContext放到了global里去,然后我们指定MyEngine是后边应用里实际使用的的Engine:
<application name="Whatever xPortal" engine-class="com.whatever.web.xportal.MyEngine"> </application> |
(写着写着又像翻译了……不爽-_-)
第二步,在Tapestry page里取得Bean,代码如下:
<property-specification name="userService" type="com.whatever.services.service.user.UserService"> global.appContext.getBean("userService") </property-specification> |
第三步,在page对应的Java class definition增加一个abstract访问者,也就是一个abstract getter
方法。代码如下:
public abstract UserService getUserService(); |
当Tapestry实际载入页面的时候,会对类文件执行runtime code方法以增加定义了的properties,并将上边的abstract getter
方法与新建的fields挂钩起来。(瀑布汗^^|||)
ok,这就完成了。详细的example请看文档。
简单总结一下。Tapestry与Spring的整合实际上是把原本由Tapestry自己负责的Service Layer,也就是对Service/Bean的调用,交给Spring负责。实际的切入点,则在于上图所示的Engine处。