1.1 Struts2插件:
从理论上来讲,Struts 2可以与任何框架整合,甚至是现在还没有问世的框架,这听起来不可思议,但却是真的。因为Struts 2提供了一种非常灵活的可扩展方式:插件,通过各种插件,Struts 2可以与任何Java EE框架进行整合。Struts 2已经提供了各种插件,用于与大部分流行的Java EE框架进行整合。
1.2 插件概述
Struts 2的插件完全超出了Struts 1插件的概念,Struts 1中的插件只是一种类似于Listener的机制。Struts 2插件则是一个JAR文件,这个JAR文件可以用于扩展、改变或者添加Struts 2的功能。安装Struts 2插件也非常简单,只需要将该插件的JAR文件复制到Web应用中即可。
注意:JSON插件的示例来看,使用Struts 2插件是非常简单的事情。实际上,Struts 2的插件非常类似于Eclipse的插件,完全是可插拔式的。当需要使用该插件时,将该插件的JAR文件复制到Web应用的WEB-INF/lib路径下即可;如果不再需要使用该插件,删除该JAR文件即可。
每个 Struts 2 的插件 JAR 文件都必须包含一个名为 struts-plugin.xml 的配置文件, struts-plugin.xml文件的内容与普通的struts.xml文件内容完全相同。
把这个包含struts-plugin.xml文件的JAR文件复制到WEB-INF/lib目录下之后,Struts 2会自动加载该 JAR 文件中的 struts-plugin.xml 文件。通过这种方式,我们就可以在struts-plugin.xml文件中定义自己需要扩展的部分,这些定义几乎可以覆盖到Struts 2的绝大部分,包括:
从上面的介绍中可以看出,Struts 2的插件几乎覆盖到Struts 2框架的方方面面,特别是重定义拦截器。因为拦截器是Struts 2框架的核心,开发者可以提供自己的拦截器,并且可以改变系统默认的拦截器引用。这意味着:如果开发者愿意,完全可以自己实现Struts 2的绝大部分底层功能。当然,一般没有这个必要,而且绝对不推荐这么做。
对于Struts 2所需要的大部分通用工作,例如与Spring、JSF、SiteMesh等框架的整合, Struts 2都提供了相应的插件。
值得指出的是,当容器中使用多个Struts 2插件时,每个插件加载的顺序是随机的,尽量不要让一个插件依赖于另一个插件(因为可能出现的情形是,被依赖的插件还没有加载,此时将导致依赖于该插件的插件无法正常运行)。
到目前为止,Struts 2 应用中可以包含三种类型的配置文件:struts-default.xml(包含在struts2-core.2.3.1.2.jar文件中)、struts-plugin.xml(包含在各插件JAR文件中)和struts.xml(应用相关的配置文件,当然也可以使用include将一个文件拆分成多个配置文件)。
为了在Web应用中使用Spring框架,当然需要将Spring框架的JAR文件复制到Web应用中。正如前面所介绍的,通常建议复制dest路径下的spring.jar文件,这个文件是Spring框架最全的类库,使用该文件比使用分模块的类库更加简单。
除此之外,Spring 框架还依赖于 commons-logging.jar 文件,因此还需要将该文件复制到Web应用的WEB-INF/lib路径下。
为了完成Spring和Struts 2的整合,还必须安装Struts 2的Spring插件。正如前面所介绍的,安装Struts 2插件是非常简单的,只需要将struts2-spring-plugin-2.3.1.2.jar文件复制到Web应用的WEB-INF/lib路径下即可。
一旦在Web应用中安装了Spring插件,即可充分利用该插件提供的如下功能。
除此之外,在使用Spring容器之前,必须先完成Spring容器的初始化。为了完成Spring容器的初始化,Spring提供一个ContextLoaderListener类,该类可以作为Web应用的 Listener使用,它会在Web应用启动时自动查找WEB-INF/下的applicationContext.xml配置文件(Spring的配置文件),并且根据该文件来创建Spring容器。
因此,如果Web应用中只有一个Spring配置文件,文件名为“applicationContext.xml”,并将该文件放在Web应用的WEB-INF路径下,则只需在web.xml文件中增加如下一段即可。
<!-- 根据默认配置文件来初始化Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
如果有多个配置文件需要载入,则应该使用<context-param>元素来确定配置文件的文件名。ContextLoaderListener加载时,会查找名为“contextConfigLocation”的参数。因此,配置context-param时指定的参数名应该是“contextConfigLocation”。
其中CONFIG_LOCATION_PARAM 是该类的常量,其值为contextConfigLocation。可以看出:ContextLoader首先检查servletContext中是否有contextConfigLocation参数,如果有该参数,则加载该参数指定的配置文件;加载该参数后,将该参数以指定的符号分解成字符串数组,每个字符串元素指定一个配置文件。
因此,如果应用中的Spring配置文件有多个,则应该采用如下形式的web.xml文件来创建Spring容器。
<?xml version="1.0" encoding="GBK"?>
<!-- 配置Web应用配置文件的根元素,并指定配置文件的Schema信息 -->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<!-- 指定多个Spring的配置文件 -->
<context-param>
<!-- 配置一个contextConfigLocation参数 -->
<param-name>contextConfigLocation</param-name>
<!-- 多个配置文件之间以,隔开 -->
<param-value>/WEB-INF/daoContext.xml ,/WEB-INF/applicationContext.xml</param-value> </context-param> <!-- 采用Listener完成Spring容器的初始化 --> <listener>
<listener-class>org.springframework.web.context.ContextLoader Listener </listener-class>
</listener>
</web-app>
如果没有 contextConfigLocation 指定配置文件,则 Spring 自动查找 WEB-INF 路径下的“applicationContext.xml”配置文件;如果有contextConfigLocation,则利用该参数指定的配置文件来创建Spring容器;如果无法找到合适的配置文件,Spring将无法正常初始化。
2.3 整合Spring的思考
对于一个基于B/S架构的Java EE应用而言,用户请求总是向MVC框架的控制器请求,而当控制器拦截到用户请求后,必须调用业务逻辑组件来处理用户请求。此时有一个问题:控制器应该如何获得业务逻辑组件?
最容易想到的策略是,直接通过 new 关键字创建业务逻辑组件,然后调用业务逻辑组件的方法,根据业务逻辑方法的返回值确定结果。
在实际的应用中,很少见到采用上面的访问策略,因为这是一种非常差的策略。不这样做至少有如下三个理由。
控制器直接创建业务逻辑组件,导致控制器和业务逻辑组件的耦合降低到代码层次,不利于高层次解耦。