内容


IBM WebSphere 开发者技术期刊

为 IBM WebSphere Application Server 开发 Spring 应用程序——第 1 部分

Spring 介绍

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: IBM WebSphere 开发者技术期刊

敬请期待该系列的后续内容。

此内容是该系列的一部分:IBM WebSphere 开发者技术期刊

敬请期待该系列的后续内容。

摘自 IBM WebSphere 开发者技术期刊

引言

如果您经常访问 Java™ 社区,那么可能听说过 Spring Framework,它在最近几年已引起了广泛的关注。

Spring 是一种分层的 J2EE 应用程序框架,该应用程序框架基于 Rod Johnson 的著作 Expert One-on-One J2EE Design and Development 一书中发布的代码,旨在通过提供一种灵活的基础结构来简化 J2EE 项目的开发。您可将 Spring 设想成帮助您在任何 J2EE 项目中实现多种所需最佳实践的工具。

在本文中,我们将假设您具有一定的 J2EE 开发经验,但从未接触过 Spring。因此,本文将首先介绍 Spring 及其优点,并通过创建一个简单的 Java 项目来演示 Spring 控制反转(Inversion of Control,IOC)和面向方面编程(Aspect-Oriented Programming,AOP)的使用。在完成基本知识介绍之后,我们将使用 IBM Rational Application Developer(以下称为 Application Developer)开发一个基于 Struts 的 Web 应用程序,并讨论如何将 Spring 和 Struts 进行集成。事实上,我们应该称之为将 Struts 集成到 Spring,因为最终是由 Spring 对 Struts 进行控制的。

在第 2 部分中,我们将讨论如何使用 WebSphere Application Server 中提供的各种连接池和事务管理选项;第 3 部分则讨论如何在我们的应用程序中集成流行的 OR 映射框架,例如 Hibernate 或 iBatis,并演示如何通过 Spring 更方便地访问 EJB 组件(Spring 包含对简化 EJB 开发的支持)。

不过,首要的事情是,我们需要回答:

什么是 Spring?

Spring 的主要思想是在传统 Java 对象(plain old Java objects,POJO)内部实现业务逻辑而不必考虑基础结构,进而简化 J2EE 开发。这一思想与 EJB 组件类似,差别在于 Spring POJO 可以在容器之外使用。

例如,设想您正在开发一个联系人管理应用程序,其中您使用了 ContactEJB。现在,当您编写 ContactEJB 的代码而不是诸如事务边界或安全需求等硬连线代码时,可以创建替代的 Java 类(需要遵守一些协议,例如 Home 和 Remote 接口)并在其中实现业务逻辑。然后,在某个 XML 文件中指定如何应用基础结构服务(如事务和安全性)。在运行时,容器将拦截您的方法调用并关注事务和服务。Spring 可提供同样的功能,并且无需使用容器。

Spring 的功能可分为三个主要部分:

  • 核心 Spring

    在其核心中,Spring 是一个 Inversion of Control (IOC) 容器。Inversion of Control 有时也称为 Dependency Injection

    设想您要编写一个名为 ContactDAO.java 的类,该类与数据库进行交互来执行联系人插入、更新和删除操作。您的类需要到数据库的连接。有两种方式可以获得此连接。第一种,您可使用加载驱动程序,进而调用 DriverManager.getConnection(),然后使用与其他 DAO 类似的代码。这可能并不适用于生产代码,因此您需要使用一个名为 getConnection() 的静态方法来创建一个独立 (singleton) 类。您所有的 DAO 都将使用该方法来获得数据库连接。在本例中,您将提取出依赖项;ContactDAO.java 类知道它需要 java.sql.Connection 类型,因而调用独立类的静态方法以获得此对象。

    Dependency Injection 建议了另外一种解决问题的方法,即在 ContactDAO.java 类中添加名为 setConnection() 的方法,并创建一个 XML 配置文件来将 ContactDAO.java 声明为 Bean。您还需要创建一个 Connection 对象作为另外的 Bean,并声明 ContactDAO Bean 依赖于 Connection Bean。然后,创建 Connection 对象(也定义成一个 Bean)并通过调用 setConnection() 方法将其注入到 ContactDAO.java 中。这可能看起来有大量工作需要做,但如果将来您打算更改应用程序连接管理方式时,只需更改 XML 中的某个定义即可。不是太有说服力?在下一部分中,我们将开发一个简单的 Java 项目示例来阐释 IOC 的工作方式。

  • Spring AOP

    面向方面编程是 Spring 中涉及的另外一个术语。简而言之,应用程序中通常包含两种不同用途的代码,一种是实现应用程序的核心/业务逻辑功能,另一种是执行系统级的任务,例如日志记录等,它们不会应用到任何特定的类或模块。创建来管理此类系统及功能的模块被称为方面模块。

    在我们的 ContactDAO.java 方法示例中,我们要在每个方法的入口和出口处记录日志。通常,在每个方法的开始,我们会通过代码检查是否已启用日志,如果已启用,则向日志记录器写一条消息。这种基本方法也带来基本的问题,由于日志记录代码将贯穿于整个应用程序中,潜在的问题就是开发人员可能会忘记在某些方法中写日志。Spring AOP 则建议不要在每个类中编写日志记录代码。它是专门创建独立的类来生成日志,然后使用 Spring 拦截器来拦截每个对 ContactDAO.java 类的方法调用。Spring AOP 然后将控制传递给您的日志记录器以生成日志。在本例中,生成日志的类可作为一个方面模块进行引用。

  • Spring 模块

    Spring 提供了现成、丰富的模块集合,这当然也是它的主要优点之一。这些模块可提供大多数常用的 J2EE 应用程序功能:

    • 连接管理:您可使用现成的 Bean 并为其提供 JDBC 驱动程序名称、JDBC URL、用户名和密码,以便它能为您管理连接池。或者,您可使用 Bean 并为其提供数据源的 JNDI 路径,使用它返回来自 WebSphere Application Server 所维护的连接池中的一个连接。
    • 数据访问 ——Spring 在本例中提供两种机制:一种是其自身的对象关系映射框架,另一种是一套模板,帮助您方便地使用流行的 OR 映射框架,例如 Hibernate 或 iBatis。
    • MVC 框架 ——Spring 提供大量的选项,以便于您选择使用所需的 MVC 框架。例如,您可使用 Spring 自身的 MVC 框架,或选择任何一种流行的框架,例如 Struts 或 JavaServer Faces。
    • 企业服务 ——Spring 还可简化对 JNDI 的访问并执行其他复杂的企业级任务。

这些当然只是 Spring 所有功能中的一部分。在本系列的文章中,我们将着重介绍如何在 WebSphere Application Server 内部使用 Spring。阅读这些文章之后,您将对其具有基本的认识,并可以此为基础学习 Spring 的其他方面功能,例如如何生成 Jasper 报告、如何在 portlet 中使用 Spring、以及模仿测试等等。

Spring IOC 项目示例

我们将构建一个简单的联系人管理应用程序来演示 Spring Dependency Injection。实际上,“联系人管理”应用程序仅包含对数据库表 CONTACT 执行插入、更新、删除和选择操作,但通过这一简单的 Java 项目示例,您就可以从其开始使用 Spring。在本文后面(以及本系列其他文章中),我们将以此示例为基础进行构建,并介绍 Spring 的其他方面功能。

最后,我们将完成的任务包括:

  • 首先,我们将定义一个 ContactDAO.java 接口,其中定义与数据库表 CONTACT 进行交互所需的业务操作。
  • 我们将创建两个不同的实现类:ContactDAOJDBC.java,将使用 JDBC 代码与 CONTACT 表交互,而 ContactDAOHibernate.java 则会使用 Hibernate 作为 OR 映射框架来与 CONTACT 表进行交互。
  • ContactDAOClient.java 为小的 Java 项目,依靠 contactDAO bean 访问 CONTACT 表。
  • 您将看到如果通过在 Spring XML 进行单个改动就能使 ContactDAOClient.java 使用 JDBC 实现而不是 Hibernate,或使用 Hibernate 而不是 JDBC。

尽管我们所使用的示例应用程序非常简单,但通过这些练习,完全可以展示 Spring 的优势。

  1. 在 Rational Application Developer 中创建名为 HelloSpring 的小 Java 项目。(图 1)

    图 1. 在 Rational Application Developer 中创建 Java 项目
    在 Rational Application Developer 中创建 Java 项目
    在 Rational Application Developer 中创建 Java 项目
  2. Spring Framework 网站上下载 spring-framework-2.0-m1-with-dependencies.zip 文件。

  3. 将此文件解压缩到您的本地 C:\ 目录,然后将 C:\spring-framework-2.0-m1\dist\spring.jar 添加到您的构建类目录中。

  4. 将 C:\spring-framework-2.0-m1\lib\jakarta-commons\commons-logging.jar 和 C:\util\spring-framework-2.0-m1\lib\log4j\log4j-1.2.9.jar 添加到类路径中。

  5. 创建一个名为 ContactDAO.java 的接口,其中定义客户端访问 CONTACT 数据库表所需的全部业务方法(参见清单 1)。

    清单 1. ContactDAO.java 的 Java 源代码
    public interface ContactDAO {
    	public void insertContact(Contact contact);
    	public List getContacts();
    	public Contact getContact(int contactId);
    	public void updateContact(Contact contact);
    	public void deleteContact( int contactId);
    }
  6. 创建 Contact.java 作为数据传输对象,用来携带 CONTACT 表数据。Contact.java 的一个实例代表 CONTACT 表中的一行数据(清单 2)。

    清单 2. Contact.java 的 Java 源代码
    public class Contact {
    	int contactId;
    	String firstName;
    	String lastName;
    	String email;
    	public int getContactId() {
    		return contactId;
    	}
    	public void setContactId(int contactId) {
    		this.contactId = contactId;
    	}
    	// Add getter setter methods for all other instance variables	
    }
  7. 如前面所提到的,我们将对 ContactDAO.java 类进行两种实现:一种是使用 JDBC 代码来访问数据库,另一种则使用 Hibernate。

    创建简单的 ContactDAOJDBC.java 文件,其中不包含任何实际的数据库交互逻辑,如清单 3 所示。

    清单 3. ContactDAOJDBC.java 的 Java 源代码
    public class ContactDAOJDBC implements ContactDAO{
    	public void insertContact(Contact contact) {
    		System.out.println("Inside ContactDAOJDBC.insertContact() method");
    	}
    	public List getContacts() {
    		System.out.println("Inside ContactDAOJDBC.getContacts() method");
    		return new ArrayList();
    	}
    	// Other business methods
    }
  8. 现在,创建与以上结构相同的 ContactDAOHibernate.java 文件,唯一的不同之处在于这里将消息写到 System.out,这便于我们区分是在使用 ContactDAOHibernate.java 而不是 ContactDAOJDBC.java。(稍后将讨论具体实现。)

  9. 接下来,创建 contactcontext.xml 文件,该文件是 Spring 使用的配置文件(参见清单 4)。

    清单 4. contactcontext.xml 的代码清单
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    	<bean id="contactDAOJDBC" class="com.sample.dao.ContactDAOJDBC"/>
    	<bean id="contactDAOHibernate" class="com.sample.dao.ContactDAOHibernate"/>
    	<bean id="contactDAOClient" class="com.sample.ContactDAOClient">
    		<property name="contactDAO">
    			<ref bean="contactDAOJDBC"/>
    		</property>
    	</bean>
    </beans>

    该配置文件用于为应用程序定义 Bean 以及这些 Bean 之间的依赖关系。元素 <bean> 用于定义 Bean,属性 id 用于定义 Bean 的名称,属性 class 定义完整的类名称。

    注意,contactDAOClient bean 的定义中使用元素 <property> 来定义依赖项。在 contactDAOClient bean 示例中,我们称它具有一个 contactDAO 属性。元素 <ref> 表示 Spring 应创建由 Bean 属性值定义的 Bean 的实例,并将其设置为 contactDAO 属性的缺省值。

    这样,当您向 Spring 请求 contactDAOClient 的一个实例时,Spring 将发现它具有一个名为 contactDAO 的属性,该属性引用 contactDAOJDBC 本地 Bean。它将创建 contactDAOJDBC Bean 所定义的 Bean 对象,即 ContactDAOJDBC.java,并在 contactDAOClient Bean 中进行设置。

  10. 创建依赖于 ContactDAO.java 的 ContactDAOClient.java 文件,如下所示:

    清单 5. ContactDAOClient.java 的 Java 源代码
    public class ContactDAOClient {
    ContactDAO contactDAO;
    public void setContactDAO(ContactDAO contactDAO) {
    	this.contactDAO = contactDAO;
    }
    public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("contactcontext.xml");
    ContactDAOClient contactDAOClient = (ContactDAOClient)ctx.getBean("contactDAOClient");
    System.out.println("Inside ContactDAOClient.main " + 
    contactDAOClient.contactDAO.getContact(1));
    //Few more operations
    }
    }

    ContactDAOClient.java 方法的 mail 方法中,我们通过创建 ClassPathXmlApplicationContext 的实例并将其完整路径传递到 contactcontext.xml 来初始化应用程序。

    Spring 加载此文件后,我们将向 Spring 请求 contactDAOClient bean,调用 getContact() 方法以查看是否在调用 ContactDAOJDBC.java 方法,更改 contactcontext.xml 可使 contactDAOClient 依赖于 contactDAOHibernate 而不是 contactDAOJDBC,然后重新运行示例项目。您将看到现在 ContactDAOHibernate.java 的方法将被调用。

在示例项目中使用 Spring AOP

现在,我们将注意力转到 Spring 的另一个非常重要的方面:AOP。这里,我们将通过两种方式更改我们的 HelloSpring 应用程序:

  • 首先,我们将创建 ContactLogger.java,其中包含在每个方法的入口和出口处生成一条日志记录的代码。
  • 我们将更改 contactcontext.xml,以便将该方面应用到 ContactDAO.java 中定义的每个方法。

在开始更改 HelloSpring 应用程序之前,我们先介绍 Spring AOP 常用的一些术语:

  • 方面——您正在实现的横切功能。在本例中,我们的方面为日志记录功能。
  • 建议——方面的实际实现。在本例中,我们的建议将包含在 ContactLogger.java 中,因为其中包含负责生成实际日志的代码。
  • 切入点——定义建议将应用到的联接点。在我们的示例中,我们打算在每个方法的入口和出口处应用我们的建议。
  • 目标——目标是指被建议的类。在本例中,我们将在 ContactDAOJDBC.java 应用建议。
  • 代理 ——代理是生成用于应用建议的类。

Spring AOP 通过方法调用拦截方式进行工作。在本例中,我们通知 Spring 所有对 ContactDAOJDBC.java 的方法调用都应被拦截,因为我们要在进入 ContactDAOJDBC.java 方法之前生成一条日志记录,并在退出 ContactDAOJDBC.java 方法之后再次生成一条日志记录。为实现此目标,我们使用了 ContactDAOLogger.java 类,它负责生成日志记录。因此,工作情况为:在运行时,Spring 将拦截所有来自客户端对 ContactDAOJDBC.java 方法的调用。在拦截每个调用之后,它首先将控制权传递给 ContactDAOLogger.java 类,以便后者能生成一条日志记录(在方法入口日志之前)。一旦写入日志,控制权将被传递给实际的 ContactDAOJDBC.java 方法,然后该方法将执行特定的业务逻辑。完成之后,控制权重新回到 Spring 框架。此时,我们希望在方法退出(由 ContactDAOLogger.java 类执行)之后生成一条日志。一旦生成退出日志,控制权就将返回给该方法的客户端。按照以下步骤完成我们的示例:

  1. 将 log4j.jar 添加到 classpath 中。该 jar 文件位于 C:\spring-framework-2.0-m1\lib\log4j 文件夹内。

  2. 在您的 Java 源代码根文件夹下创建 Create log4j.xml(参见清单 6)。

    清单 6. log4j 代码清单示例
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern"
                    value="%p - %C{1}.%M(%L) | %m%n"/>
            </layout>
        </appender>
        <logger name="org.springframework.aop.interceptor">
            <level value="DEBUG"/>
        </logger>
        <root>
            <level value="INFO"/>
            <appender-ref ref="CONSOLE"/>
        </root>
    </log4j:configuration>
  3. 现在,我们将创建 ContactLogger.java 文件,该文件将负责在进入 ContactDAOJDBC.java 的每个方法之前或退出之后生成日志记录(清单 7)。

    清单 7. ContactLogger.java 的 Java 代码
    public class ContactLogger implements MethodBeforeAdvice,AfterReturningAdvice{
    	public void before(Method method, Object[] arguments, Object target) 
    	throws Throwable {
    		System.out.println("ContactLogger.before " + method);
    	}
    	public void afterReturning(Object returnValue, Method method, 
    	Object[] arguments, Object target) throws Throwable {
    	System.out.println("ContactLogger.afterReturning " + method);
    	}
    }

    如清单 7 所示,ContactLogger.java 实现两个接口,即 MethodBeforeAdvice 和 AfterReturningAdvice。Spring 将在调用 ContactDAOJDBC.java 的任何方法之前将控制权传递给 before() 方法,并在返回控制权之后再传递给 afterReturning() 方法。

  4. 如清单 9 所示,更改 contactcontex.xml 文件。

    清单 9. contactcontext.xml 中的代码清单
    <bean id="contactDAOClient" class="com.sample.ContactDAOClient">
    	<property name="contactDAO">
    		<ref local="contactDAOLogger"/>
    	</property>	
    </bean>
    <bean id="contactLogger" class="com.sample.logging.ContactLogger"/>
    <bean id="contactDAOLogger" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    	<property name="proxyInterfaces">
    		<list>
    			<value>com.sample.ContactDAO</value>
    		</list>
    	</property>	
    	<property name="interceptorNames">
    		<list>
    			<value>contactLogger</value>
    		</list>
    	</property>
    	<property name="target">
    		<ref bean="contactDAOJDBC"/>
    	</property>
    </bean>

    其中最重要的 Bean 定义是对 contactDAOLogger Bean 的定义,该 Bean 被配置到 ProxyFactoryBean 的路径。ProxyFactoryBean 用于创建由 interceptorNames 定义的接口的代理类。

    现在,当您向 Spring 框架请求 contactDAO bean 的对象时,它会将控制权传递给 ProxyFactoryBean 类。该类将首先查找确定需要为哪个接口提供代理,在本例中,ContactDAO.java 是 proxyInterfaces 属性中列出的唯一接口。现在,我们已经拥有了代理,但我们还要找出哪个是实际的实现类。属性 target 定义了负责执行业务逻辑的类,在本例中为 contactDAOJDBC。

    初始设置完成后,ProxyFactoryBean 将通过创建实际类的代理来创建一个隧道。当您在任何时候调用 contactDAO 代理的方法时,它都将被拦截,同时控制权将被传递给拦截器,拦截器是由 interceptorNames 属性进行定义,在本例中为 contactLogger。该拦截器将拦截方法调用并执行相应的逻辑(即生成方法进入或退出的消息)。拦截器完成操作之后,控制权又将被传递回类中,在本例中为 ContactDAOJDBC.java。

    尝试运行该程序,您将看到 ContactLogger 生成的日志记录,该记录非常的简单。不过,您还可将 interceptorNames 属性更改成 contactTraceInterceptor 或 simpleTraceInterceptor,这是两种另外的拦截器,它们具有略微高级的功能。您可下载示例代码以获得这两个类的实现。

阅读此时序图以理了整个工作情况。

图 2. Spring AOP 时序图
Spring AOP 时序图
Spring AOP 时序图

在您调用 getBean("contactDAOJDBC") 方法时,Spring 框架将返回 ProxyFactoryBean 的实例,并以其作为代理类在客户端和目标之间建立一个隧道 (contactDAOJDBC)。然后,只要在此代理上进入或退出方法,都将被拦截,并且控制权将被传递给 ContactLogger.java' before() 方法。在控制权返回之后,它将被传递给实际的 ContactDAOJDBC.java 类方法。一旦 ContactDAOJDBC.insertContact() 方法正常结束,代理类就将重新获得控制权。完成之后,它将调用 ContactLogger 的 afterReturningAdvice() 方法。然后,控制权返回给客户端。

在讨论事务管理的主题时,我们将相当多地使用 AOP,因此您需要通过实验来确保对其完全理解。

将 Struts 和 Spring 相集成

Spring 允许您在开发 Web 应用程序时从多种 MVC 框架中进行选择。在本文中,我们将使用 Struts MVC 框架,因为 IBM WebSphere Studio Application Developer 和 Rational Application Developer 都提供了方便易用的工具来开发 Struts 应用程序,而且目前 Struts 已得到广泛应用,您可能已经非常熟悉这一框架。如果您是 Struts 的新手,则可通过足够的文档来学习相关知识(请参阅参考资料)。

在 Struts MVC 框架中,当用户发出请求时,控制权将首先传递给 Controller servlet。通过 RequestProcessor 的帮助,Controller servlet 将确定用户请求的操作并创建相应的 Action 类实例。需要特别注意的是,Struts Action 类并不是线程安全的,也就是说,Controller 将创建 Action 类的单个实例并用它来服务所有请求。这意味着 Action 类中无法具有实例变量,但可以使用方法变量。

在将 Struts 和 Spring 进行集成时,您通常具有两种一般性选择:

  • 使用 ContextLoaderPlugin 配置 Spring 以将 Action 作为 Bean 进行管理。在您集成 Struts 1.1+ 应用程序和 Spring 时,可使用此方法。此时,Spring 将为每个客户端请求创建新的 Action 类实例。Action 类也可配置成一个 Bean,这样 Spring 可将依赖项作为实例变量注入其中。不必担心为每个请求创建新的 Action 类会引起性能问题,实际上影响是完全可以忽略的。

  • 使用 getWebApplicationContext() 方法继承 Spring ActionSupport 类并显式地获取 Spring 管理的 Bean。在此方法中,只使用 Action 类的单个实例来处理所有的用户请求,在此实例中,您可在执行方法内使用 getWebApplicationContext() 方法来获得 WebApplicationContext 对象。一旦拥有此 WebApplicationContext 实例,您就可以调用其 getBean() 方法来获取依赖项。

在我们的联系人管理应用程序实例中,我们将采用原来使用 ContextLoaderPlugIn 的方法,因为这更加符合 Spring 应用程序的风格。如果您要采用继承 ActionSupport 的方法,可参阅 Spring 文档。

  1. 创建一个名为 ContactMang 的新 Struts 动态 Web 项目。缺省情况下,Rational Application Developer 将使用 Struts 版本 1.1,如果您使用的是 WebSphere Studio Application Developer,您将需要手动选择此 Struts 版本。

  2. 将 HelloSpring.jar 导入到 Web Content/WEB-INF/lib 文件夹。

  3. 从 HelloSpring 将 contactcontext.xml 文件导入到 /Web Content/WEB-INF,并将 log4j.xml 文件导入到 /Web Content/WEB-INF/classes 文件夹中。

  4. 记住,需要将依赖项 JAR 文件(如 log4j.jar 和 spring.jar)导入到您的 /Web Content/WEB-INF/lib 文件夹中。Struts 附带有 commons-logging.jar 文件,因此无需导入。

  5. 如清单 10 所示,更改 struts-config.xml 文件。

    清单 10. struts-config.xml 中的源代码清单
    <controller processorClass="org.springframework.web.
    struts.DelegatingRequestProcessor">
    </controller>
    <message-resources parameter="com.ibm.contactmang.resources.
    ApplicationResources"/>
    <plug-in className="org.springframework.web.struts.
    ContextLoaderPlugIn">
    <set-property property="contextConfigLocation" 
    value="/WEB-INF/actionServlet.xml,/WEB-INF/contactcontext.xml"/>
    </plug-in>

    在此文件中,我们做两件事。首先,我们定义 ContextLoaderPlugIn 并请求 Struts 使用我们自定义的 RequestProcessor 来加载上下文文件。缺省情况下,它将尝试将 /WEB-INF/action-servlet.xml 文件加载到 Spring 的 Bean 定义中,但在本例中,上下文定义被划分在两个文件中:actionServlet.xml 和 contactcontext.xml,这就是我们要设置 contextConfigLocation 属性的原因。DelegatingRequestProcessor 类是非常简单的类,它是对缺省 RequestProcessor 类的扩展。它只覆盖 Action 类的创建方法,例如 processActionCreate(),尝试通过 struts-config.xml 中的映射名称来从 contactcontext.xml 确定 Action 类。

  6. 创建 SelectContactAction.java 类,如清单 11 所示。

    清单 11. SelectContactAction.java 的 Java 代码清单
    public class SelectContactAction extends Action{
    	private ContactDAO contactDAO;
    	public void setContactDAO(ContactDAO contactDAO) {
    		this.contactDAO = contactDAO;
    	}
    	public ActionForward execute(ActionMapping mapping, ActionForm form,
    	HttpServletRequest request, HttpServletResponse response) 
    	throws Exception {
    	System.out.println("Inside SelectContactAction.execute() ");
    	List contactList = contactDAO.getContacts();
    	request.setAttribute("contactList" ,contactList);
    	return mapping.findForward("sucess");
    	}
    }

    现在,我们使用 SelectContactAction.java 代替 ContactDAOClient.java 作为 ContactDAO.java 的客户端,因此 Spring framework 将创建 ContactDAO.java 的实例,并使用 setContactDAO 方法将其注入到 SelectContactAction 对象中。我们将调用 getContacts() 方法来进行验证。此外,请记住从实例代码中导入 ContactForm.java。

  7. 在您的 struts-config.xml 文件 qas 中添加用于 /selectContact 操作的条目,如清单 12 所示。

    清单 12. struts-config.xml 的代码清单
    <action-mappings>
    <action path="/selectContact" 
    type="org.springframework.web.struts.DelegatingActionProxy" 
    name="contactForm" scope="request">
    	<forward name="sucess" path="ContactList.jsp"  />
    	<forward name="failure" path="Failure.jsp"  />
    </action>
    </action-mappings>

    注意,/selectContact 并不是映射到 com.sample.SelectContactAction,而是映射到 org.springframework.web.struts.DelegatingActionProxy 类。Spring 使用 DelegatingActionProxy 代理类,以在控制权被传递给实际的 Action 类之前将其获得。在该类的 execute() 方法中,Spring 将确定实际 Action 类的名称,并将控制权传递给其 execute() 方法。

  8. 在 actionServlet.xml 文件中将 SelectionAction 声明为 Bean。

    清单 13. actionServlet.xml 的代码清单
    <bean name="/selectContact" singleton="false" autowire="byName" class="com.sample.SelectContactAction">
    	<property name="contactDAO">
    		<ref bean="contactDAO"/>
    	</property>	
    </bean>

    在此处,我们指定用于处理实际请求的 Action 类。具体做法是将操作路径映射到 Bean 名称。属性 singleton="false" 用于指定需要为每个请求创建新的 SelectContactAction 类实例。从示例代码中导入 index.jsp、ContactList.jsp 和 Failuer.jsp。

  9. 现在您可编译该项目并将其部署到 WebSphere Application Server 上。当您尝试访问 /selectContact 操作时,Spring 将拦截调用并创建一个 contactDAO 实例。这将使用 setter 方法在 SelectContactAction 对象中设置此实例。最后, DelegatingActionProxy.execute() 方法会将控制权传递给 SelectContactAction.execute() 方法。确保您现在能看到联系人列表,因为在下一篇文章中我们将更改 ContactMang 应用程序以访问实际的数据库。

如果您要使用其他的 MVC 框架,例如 JSF、WebWorks 或 Spring 自己的 MVC 框架,可参阅 Spring 联机文档以获得相应步骤的说明。

结束语

在本文中,我们讨论了有关 Spring 框架的基本概念,使您开始对其有一定认识。在接下来的两篇文章中,我们将花更多的时间来解决企业应用程序开发人员所面临的问题,特别是连接和事务处理方面的问题,同时还将使用 WebSphere Application Server 提供的某些企业级服务。

作为本系列的第一篇文章,本文主要向您概述了 Spring 框架。文中无法涵盖所有特性,甚至也不可能涵盖 Spring 必须提供的主要特性。我们的目的在于帮助充分了解 Spring 的基本知识,以便您自己能够继续探索 Spring 框架。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, Java technology, Rational
ArticleID=111647
ArticleTitle=IBM WebSphere 开发者技术期刊: 为 IBM WebSphere Application Server 开发 Spring 应用程序——第 1 部分
publish-date=05082006