技术开发 频道

Spring 2.0集成Tapestry 5.0

   【IT168 技术文档】概述

   Tapestry是一个基于组件的Web框架,以至于用它开发Web应用和开发传统的GUI应用很类似。使用Tapestry开发Web应用时,你无须关注以操作为中心Servlet API,引用Tapestry网站上的一句话:“Tapestry用对象、方法、属性替代以往的URL和查询参数,重新诠释Web应用开发”。

   当前Tapestry的最新版本是5.0,新版本添加了很多新的功能,其中最让人感慨的是,Tapestry原有的IoC功能,现在已经越来越弱化,Tapestry将在不久将来完全放弃自身的IoC实现,转而使用Spring IoC。和Struts 2一样,Tapestry 5.0也专门提供了一个集成将Tapestry集成到Spring中的插件——对于Spring来说,越来越有“朵朵向阳开,高歌欢庆新春来”的气息了。

   Tapestry为集成Spring提供的类

   Tapestry 5.0提供了一个用于集成Spring中的tapestry-spring-5.0.x.jar类包,该类包中有三个重要的类,下面我们分别对此进行简单的说明。

   ·SpringObjectProvider:ObjectProvider的实现类,它从Spring容器中获取Bean;
   ·SpringBean:这是一个注解类,你可以在Tapestry类的属性变量或方法入参中标注该注解,这样Tapestry就会自动根据SpringObjectProvider从Spring容器中获取对应的Bean并完成动态注入;
   ·SpringModule:Tapestry使用该类保存Spring容器的引用,确切地说它包含了WebApplicationContext实例的引用。

   SpringObjectProvider

   我们知道Tapestry拥有一套自己的IoC实现,其中org.apache.tapestry.ioc.ObjectProvider是Tapestry IoC的重要接口,它相当于Spring的BeanFactory,负责创建并返回Bean的实例。SpringObjectProvider实现了ObjectProvider接口,它不去亲自创建Bean实例,相反它通过访问Spring容器获得Bean实例。
代码清单 4 SpringObjectProvider package org.apache.tapestry.spring; … public class SpringObjectProvider implements ObjectProvider { … public SpringObjectProvider(Log log, @InjectService("WebApplicationContext") WebApplicationContext context) ①通过Tapestry的基础设施注入Spring容器引用 { _log = log; _context = context; } private synchronized void loadBeanNames() { … } public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator) ② 从Spring容器中获取Bean { SpringBean annotation = annotationProvider.getAnnotation(SpringBean.class); if (annotation == null) return null; String beanName = annotation.value(); Object raw = _context.getBean(beanName, objectType); return objectType.cast(raw); } }

   该类在实例化时,Tapestry框架会将Spring容器的WebApplicationContext引入传递进来,通过
   ①处的构造函数你可以清楚地看到这点。
   ②处的方法是ObjectProvider接口的方法,这个方法看起来挺奇怪,这是因为Tapestry 5.0已经不采用基于XML的配置机制,相反它采用JDK 5.0注解的机制直接在类中通过注解进行装配。如果Tapestry组件类的属性或方法入参需要使用Spring容器的Bean进行注入,只需要标注上@SpringBean就可以了,Tapestry框架通过扫描组件类,为所有标注了@SpringBean的属性或入参注入Spring中的Bean。由于@SpringBean包含了Bean的名字,而被标注的属性或入参提供了对象的类型,这样SpringObjectProvider就可以按“名字+类型”获取Spring中相应的Bean了。

   SpringBean

   SpringBean是一个标准的JDK 5.0注解类,用于标注Tapestry组件类的成员变量和方法入参,为Tapestry框架提供元数据信息,以便使用Spring容器中的Bean对标注对象进行依赖注入。
package org.apache.tapestry.spring; … @Target({ FIELD, PARAMETER }) ①可以用于标注成员变量和方法入参 @Documented @Retention(RUNTIME) public @interface SpringBean { String value(); ②可以通过值指定需要注入的Bean名称 }

  SpringModule

    SpringModule从ServletContext中获取WebApplicationContext,并将SpringObjectProvider注册为ObjectProvider的实现类,SpringModule将作为Tapestry的一个基础设施。

package org.apache.tapestry.spring; import org.apache.tapestry.ioc.ObjectProvider; import org.apache.tapestry.ioc.OrderedConfiguration; import org.apache.tapestry.ioc.ServiceBinder; import org.apache.tapestry.ioc.annotations.InjectService; import org.apache.tapestry.services.Context; public class SpringModule { public static void bind(ServiceBinder binder) { ①将SpringObjectProvider作为ObjectProvider的实现类 binder.bind(ObjectProvider.class, SpringObjectProvider.class) .withId("SpringObjectProvider"); } ②注入Tapestry的Context(是Tapestry为ServletContext提供的别名类) public static WebApplicationContext build(@InjectService("Context") Context context) { WebApplicationContext springContext = (WebApplicationContext) context .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_A return springContext; } … }

   Tapestry将这些类打包在tapestry-spring-5.0.x.jar中,该JAR包中有一个MANIFEST.MF标明文件,文件中通过以下语句指定了Tapestry的模块类:

Tapestry-Module-Classes: org.apache.tapestry.spring.SpringModule

   这样,在Tapestry启动时,SpringModule类自动被初始化,并注入Tapestry的Context实例(其实就是ServletContext),这样SpringModule实例就包含Spring容器的引用了。

   在了解了Tapestry为集成Spring做了哪些准备后,下面我们将开始讨论如何通过具体配置集成Spring,让Tapestry的组件类通过注解引用Spring的Bean。

   Tapestry集成Spring的具体配置步骤

   下面是Spring的配置文件,它定义了多个Bean,我们希望Tapestry能够直接引入bbtForum Bean:

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="bbtForum" class="com.baobaotao.service.BbtForum"/></beans>

   Tapestry的组件类直接通过注解引用Spring容器中的Bean,来看一下UserRegister如何引用bbtForum Bean:

package com.baobaotao.pages; import org.apache.tapestry.annotations.Inject; import org.apache.tapestry.spring.SpringBean; public class UserRegister { @Inject @SpringBean("bbtForum") ①通过注解,Tapestry将在启动时注入Spring容器中的Bean private BbtForum _bbtForum; void onSuccess() { … } }

   在编写好通过注解引用Spring容器的Bean的组件类后,剩下的工作就是如何正确配置web.xml以便组件类能够真正注入Spring Bean并正确地工作起来:

代码清单 5 web.xml <web-app> <context-param> ① Tapestry通过该上下文参数确定应用程序类所在的包 <param-name>tapestry.app-package</param-name> <param-value>com.baobaotao </param-value> </context-param> <context-param> ② Spring配置文件 <param-name>contextConfigLocation</param-name> <param-value>classpath:baobaotao-*.xml</param-value> </context-param> <filter> ③ Tapestry过滤器,既负责初始化Tapestry,又负责截获框架处理的URL请求 <filter-name>app</filter-name> <filter-class>org.apache.tapestry.TapestryFilter</filter-class> </filter> <filter-mapping> <filter-name>app</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> ④ 初始化Spring容器 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>

   TapestryFilter扮演着重要的角色,它一方面负责初始化Tapestry框架,在初始化时就着手将Spring容器中的Bean注入到标注@SpringBean注解的组件类中;另一方面它还负责截获URL请求,以便交由Tapestry框架进行具体的处理。

   当然,我们也需要在web.xml中配置好Spring相关的配置启动Spring容器,这样Tapestry才能正确引用到Spring容器中的Bean。

   小结

   简而言之,要将Tapestry 5和Spring 2.0进行集成,你仅需要进行以下两个小小的步骤就可以了:
   1) 将tapestry-spring-5.0.x.jar添加到类路径中;
   2) 在组件类需要注入Spring容器Bean的地方使用@SpringBean注解。
   集成成功后,在Tapestry 5组件类中需要注入Spring容器中Bean的地方(可以是成员变量或方法入参)直接使用@SpringBean注解进行标注就可以了。

0
相关文章