将 Spring 和 Hibernate 与 WebSphere Application Server 一起使用

通过 WebSphere Application Server V6 至 V7 充分利用开放源代码环境

如果您考虑将 Spring 或 Hibernate 与 IBM WebSphere Application Server 一起使用,则本文将向您阐述如何为各种 WebSphere Application Server 场景配置这些框架。本文不是对任一框架的详尽评论,而是帮助您成功实现此类场景的重要参考。(针对 Spring Framework 2.5 和 WebSphere Application Server V7 进行了更新。)

摘自 IBM WebSphere 开发者技术期刊。 本文来自于 IBM WebSphere Developer Technical Journal

Tom Alcott, IT 咨询专家, IBM Software Group, Worldwide Sales

Tom Alcott 是 IBM 美国的一位 IT 咨询专家。自 1998 年 Worldwide WebSphere Technical Sales Support 小组成立以来,他就一直是该小组的成员。在此期间,他花费了大多数时间来编写用户手册。在开始研究 WebSphere 之前,他是 IBM 的 Transarc 实验室的一名系统工程师,负责支持 TXSeries。他有 20 多年从事基于大型机和分布式系统的应用程序设计与开发工作的背景。他撰写并发表了大量关于 WebSphere 运行时问题的文章。


developerWorks 专家作者

Jim Knutson, WebSphere J2EE 架构师, EMC

Jim KnutsonJim Knutson 是 WebSphere 的 J2EE 架构师。Jim 负责 IBM 参与的 J2EE 相关规范,他参与这些工作的时间要追溯到 J2EE 出现以前。Jim 还参与了编程模型的改进,以支持 SOA 和 Web 服务。



Sara Mitchell, 软件工程师, EMC

Sara MitchellSara Mitchell 在英国的 IBM Hursley 开发实验室工作,是 WebSphere Application Server 团队的负责人。



Dr. Ian Robinson, STSM 兼 WebSphere 事务架构师, EMC

Ian RobinsonIan Robinson 博士是 IBM 高级技术人员和 IBM WebSphere Application Server 的事务架构师。他在设计和实施分布式事务系统方面有超过 12 年的经验,一直从事 IBM CICS 服务器和 ComponentBroker CORBA 服务器的工作。Ian 是 OASIS Web 服务事务技术委员会的主席之一,并且是 J2EE 活动服务 (JSR 95) 规范负责人和 WS-Transaction 规范集的合著者之一。Ian 分别于 1986 年和 1989 年获得了英国埃克塞特大学物理专业学士和博士学位。



2008 年 11 月 04 日 (最初于 2006 年 11 月 04 日)

引言

Spring Framework(通常称为 Spring)是一个开放源代码项目,目的是为了使 J2EE™ 环境更具可访问性。Spring 为简单 Java™ 对象提供框架,使这些对象可以通过包装类和 XML 配置使用 J2EE 容器。Spring 的目标是为这些项目提供显著的好处,提高这些项目的开发效率和运行时性能,同时改进测试覆盖率和应用程序质量。

Hibernate 是开放源代码持久性和查询框架,提供传统 Java 对象(Plain Old Java Object,POJO)到关系数据库表的对象-关系映射,以及数据查询和检索功能。

尽管许多组织感兴趣的是了解使用这些框架能够获得什么好处,但 IBM 希望让使用这些框架的客户知道,他们可以通过 WebSphere Application Server 以稳健和可靠的方式做到这一点。本文介绍这些框架如何与 WebSphere Application Server 一起使用,并介绍针对各种用例的最佳实践,以帮助您尽快开始使用 Spring 或 Hibernate。


使用 Spring

您可以点击如下链接,马上下载 WebSphere Application Server 软件 V7 版本,体验其为您带来的新特性及新功能。

更多关于 WebSphere Application Server 的技术资源,请参考:

通常将 Spring 描述为轻量级容器环境,但是将其描述为用于简化开发的框架可能更适当。Spring Framework 由 Interface21 根据 Rod Johnson 发表的关于依赖项注入设计模式的出版物开发而成。Spring 可以在独立应用程序中使用,或与应用程序服务器一起使用。其主要概念是使用依赖项注入和面向方面的编程来简化和平稳地进行从开发到测试再到生产的转换。

涉及 Spring 的最常用场景之一是使用简单的 Java Bean 类配置并驱动业务逻辑。Spring 文档应该提供了使用 Spring Bean 构建应用程序的足够信息,其中没有提供任何特定于 WebSphere 的内容。以下部分将描述在 WebSphere Application Server 上使用 Spring 的一些使用场景。根据本文的建议开发的 Spring 应用程序应该能够毫无问题地在 WebSphere Application Server 或 WebSphere Application Server Network Deployment 环境中执行。

除明确指出以外,本文提供的信息适用于所有平台上的 WebSphere Application Server 版本 6.0.2.x、6.1.x 和 7.0.x。

表示层注意事项

本部分介绍与在基于 Web 的表示层中使用 Spring 相关的注意事项。

  • Web MVC 框架

    Spring 的 Web MVC 框架很长时间以来一直是其他框架的替代框架。直接由 WebSphere Application Server 交付、使用和支持的 Web MVC 框架包括 JavaServer Faces (JSF) 和 Struts。Spring 文档描述了如何将 Spring 与这些 Web 框架集成。尽管 WebSphere Application Server 支持使用上面的任何 MVC,但 IBM 仅为 WebSphere Application Server 附带的框架提供产品支持。

  • Portlet MVC 框架

    Spring 还提供了一个 Portlet MVC 框架(该框架镜像 Spring Web MVC 框架),而且在 WebSphere Portal V6.0 和 WebSphere Application Server V6.1 Portlet 容器中运行。(有关 Spring Portlet 的示例集,请参见 Spring Portlet MVC。)在 WebSphere Application Server V6.1 Portlet 容器中运行 Portlet 需要创建附加的 Web 应用程序,以定义 Portlet 的布局和聚合。从 WebSphere Application Server 信息中心和文章 Portlet 容器介绍中可以获得关于如何使用 Portlet 聚合器标记库的信息。通常的做法是结合使用 JSF 和 Portlet 进行呈现。关于如何将 Spring、Hibernate、JSF 和 WebSphere Portal 组合起来的信息,请参见使用 IBM WebSphere Portal 配置 Hibernate、Spring、Portlets 和 OpenInSessionViewFilter

数据访问注意事项

本部分介绍与访问事务中的数据的 Spring Bean 配置相关的注意事项。

Spring Framework 实际上使用一个容器管理层(在 J2EE 环境中委托给基础 J2EE 运行时)包装 Spring Bean。下面将介绍应如何配置 Spring Bean,以便 Spring Framework 可以正确地向 WebSphere Application Server 运行时做出委托并与之集成。

  • 访问 WebSphere Application Server 中配置的数据源

    WebSphere Application Server 管理在应用程序服务器执行环境中使用的资源。需要访问诸如 JDBC 数据源等资源的 Spring 应用程序应该利用 WebSphere 管理的资源。为此,请执行以下步骤:

    1. 在开发过程中,应该使用资源引用配置 WAR 模块。例如:

      <resource-ref>
      	<res-ref-name>jdbc/springdb</res-ref-name>
      	<res-type>javax.sql.DataSource</res-type>
      	<res-auth>Container</res-auth>
      	<res-sharing-scope>Shareable</res-sharing-scope>
      </resource-ref>
    2. 对于 EJB JAR 文件,应该在需要访问数据源的每个 EJB 中声明同一资源引用。

    3. 然后在 Spring 应用程序配置中声明数据源代理 Bean,代理 Bean 引用 WebSphere 管理的资源提供者:

      <bean id="wasDataSource" 
          class="org.springframework.jndi.JndiObjectFactoryBean">
      	<property name="jndiName" 
      		value="java:comp/env/jdbc/springdb"/>
      	<property name="lookupOnStartup" 
      		value="false"/>
      	<property name="cache" 
      		value="true"/>
      	<property name="proxyInterface" 
      		value="javax.sql.DataSource"/>
      </bean>

      通过此代理 Bean 访问数据源将会导致使用模块配置的引用查找数据源,从而能够由 WebSphere Application Server 正确管理。请注意,jndiName 属性值与使用资源引用中声明的资源引用名称连接的模式 java:comp/env/ 匹配。

      或者,在 Spring 2.5 以后的版本中,可以使用 <j2ee:jndi-lookup/> 方法完成此匹配。请注意 jndiName 属性如何匹配资源引用中声明的资源引用名称与 resource-ref="true" 属性相结合的实际值:

      <jee:jndi-lookup id=" wasDataSource "
      	jndi-name="jdbc/springdb"
      	cache="true"
      	resource-ref="true"
      	lookup-on-startup="false"
      	proxy-interface="javax.sql.DataSource"/>
    4. 然后,Spring 应用程序可以在适当情况下使用数据源代理 Bean。

    5. 将应用程序部署到 WebSphere Application Server 时,必须以常规方式配置资源提供者和资源数据源,以便由 Spring 应用程序资源引用使用。在部署过程中,在模块的部署描述符中声明的资源引用将绑定到应用程序服务器配置的数据源。

  • 使用 JDBC 本机连接

    当各种 JDBC 操作需要与本机 JDBC 资源交互时,Spring 可提供访问本机连接的机制。当在 JdbcTemplate 类上设置了 NativeJdbcExtractor 类时,Spring JdbcTemplate 类才可以利用此功能。设置 NativeJdbcExtractor 类后,当与 WebSphere Application Server 一起使用时,Spring 总是向下找到本机 JDBC 连接。这将忽略以下 WebSphere 服务质量功能和优点:

    • 连接处理跟踪和再关联
    • 连接共享
    • 参与事务
    • 连接池管理

    这带来的另一个问题是 WebSphereNativeJdbcExtractor 类将依赖于内部 WebSphere 适配器类。这些内部类可能因 WebSphere Application Server 的版本而异,并且以后可能更改,从而破坏依赖于此功能的应用程序。

    在 WebSphere Application Server 上不支持使用 NativeJdbcExtractor 类实现(例如 WebSphereNativeJdbcExtractor),您应避免需要使用该类的场景。替代方案是使用 WebSphere Application Server WSCallHelper 类来访问非标准供应商的数据源扩展。

  • 使用 Spring 处理事务

    WebSphere Application Server 为事务处理和管理与资源提供者的连接提供了一个稳健和可伸缩的环境。无论是否在使用全局事务,与 JDBC、JMS 和 Java Connector 资源适配器的连接均由 WebSphere Application Server 管理;甚至在缺少全局事务时,始终存在一个运行时上下文,在该上下文中可以访问所有资源提供者连接。WebSphere Application Server 将此运行时上下文称为本地事务容器 (LTC) 作用域;在缺少全局事务时始终存在一个 LTC,并且无论是存在全局事务还是 LTC,资源访问始终由运行时管理。为确保事务上下文管理的完整性,以便可以正确管理事务资源,WebSphere Application Server 不向 WebSphere Application Server 中部署的应用程序或应用程序框架公开 javax.transaction.TransactionManager 接口。

    在 Spring 中,有许多方法可以驱动事务控制下的资源更新,这包括编程形式和声明形式。声明形式包括 Java Annotation 和 XML 描述符形式。如果将 Spring 2.5 与 WebSphere Application Server V6.0.2.19 或 V6.1.0.9 或者更高版本一起使用,则可以利用对 Spring 的声明式事务模型的完全支持。Spring 2.5 有一个新的用于 WebSphere Application Server 的 PlatformTransactionManager 类,名为 WebSphereUowTransactionManager。该类利用 WebSphere Application Server 的受支持 UOWManager 接口进行事务上下文管理。通过 WebSphere Application Server 的 UOWManager 类管理事务划分可以确保在访问资源提供者时始终可以使用适当的全局事务或 LTC 上下文。不过,早期版本的 Spring 使用了内部 WebSphere 接口,以牺牲 Web 和 EJB 容器功能为代价来管理资源,并且不支持由应用程序使用。这会使容器处于未知状态,从而有可能导致数据损坏。

    Spring 2.5 或更高版本中的声明式事务划分在 WebSphere Application Server 中受支持,它使用下面的声明提供对 WebSphere 事务的支持:

    <bean id="transactionManager"
    	class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>

    引用此声明的 Spring Bean 然后将使用标准 Spring 依赖项注入来使用事务支持,例如:

    <bean id="someBean" class="some.class">
    	<property name="transactionManager" >
    		<ref bean="transactionManager"/>
    	</property>
    ...
    </bean>
    <property name="transactionAttributes">
    	<props>
    		<prop key="*">PROPAGATION_REQUIRED</prop>
    	</props>
    	</property>

    或者,在 Spring 2.5 以后的版本中,可以利用 Spring 的 AspectJ 支持。在下面的示例中,可以将 <tx:advice/> 应用于应用程序的各个部分。这指示所有以“get”开头的方法都是 PROPAGATION_REQUIRED,并且所有以“set”开头的方法都是 PROPAGATION_REQUIRES_NEW。所有其他方法使用缺省事务设置。

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes>
          <tx:method name="get*" propagation="REQUIRED" read-only="true" />
          <tx:method name="set*" propagation="REQUIRES_NEW" />
          <tx:method name="*" />
       </tx:attributes>
    </tx:advice>

    <aop:config/> 标记将那些设置应用于类 MyService 中定义的任何已执行操作。

    <aop:config>
       <aop:pointcut id="myServiceOperation" 
          expression="execution(* sample.service.MyService.*(..))"/>
       <aop:advisor advice-ref="txAdvice" 
          pointcut-ref="myServiceOperation"/>
    </aop:config>

    用于声明事务设置的另一种替代机制是使用基于 Spring 注释的事务支持。这要求使用 Java 5+,因此无法与 WebSphere Application Server V6.0.2.x 一起使用。

    将以下内容添加到 Spring.xml 配置:

    <tx:annotation-driven/>

    然后应该使用 @Transactional 注释对需要事务属性的任何方法进行标记:

    @Transactional(readOnly = true)
    public String getUserName()
    { ...

    请注意,只能将 @Transactional 注释用于注释公共方法。

    WebSphereUowTransactionManager 支持每个 Spring 事务属性:

    • PROPAGATION_REQUIRED
    • PROPAGATION_SUPPORTS
    • PROPAGATION_MANDATORY
    • PROPAGATION_REQUIRES_NEW
    • PROPAGATION_NOT_SUPPORTED
    • PROPAGATION_NEVER

    对于没有提供 org.springframework.transaction.jta.WebSphereUowTransactionManager 的早期 Spring 版本以及没有提供 com.ibm.wsspi.uow.UOWManager 的 WebSphere Application Server V6.0.2.19 或 V6.1.0.9 之前的版本,WebSphere Application Server 中的事务支持通过以下 Spring 配置实现:

    <bean id="transactionManager" 
    	class="org.springframework.transaction.jta.JtaTransactionManager">
    		<property name="autodetectTransactionManager"value="false" />
    </bean>

    此配置支持一组受限制的事务属性,其中不包括 PROPAGATION_NOT_SUPPORTED 和 PROPAGATION_REQUIRES_NEW。Spring 类 org.springframework.transaction.jta.WebSphereTransactionManagerFactoryBean 也宣称提供 PROPAGATION_NOT_SUPPORTED 和 PROPAGATION_REQUIRES_NEW 功能,它使用不受支持的内部 WebSphere Application Server 接口,不应将其与 WebSphere Application Server 一起使用。

  • 使用 Spring JMS

    与访问 JDBC 数据源类似,打算访问 JMS 目的地的 Spring 应用程序必须确保它们使用了 WebSphere 管理的 JMS 资源提供者。使用 Spring JndiObjectFactoryBean 作为 ConnectionFactory 代理的相同模式将确保可以正确地管理 JMS 资源。

    对于 JMS 消息发送或同步 JMS 消息接收,可以使用 JMSTemplates。这包括通过 JNDI 和真正的动态解析使用 Spring 的动态目的地解析功能。

    下面的示例演示了 ConnectionFactory 的资源引用配置。此引用在应用程序部署过程中映射为指向应用程序服务器的 JNDI 命名空间中存储的已配置托管 ConnectionFactory。ConnectionFactory 是执行消息处理所必需的,并且应该将其注入 Spring JMSTemplate。

    <resource-ref>
          <res-ref-name>jms/myCF</res-ref-name>
          <res-type>javax.jms.ConnectionFactory</res-type>
          <res-auth>Container</res-auth>
          <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>

    现在应用程序中的 ConnectionFactory 有了已定义的 JNDI 名称,可以对其进行查找并将其注入 JMSTemplate:

    <jee:jndi-lookup id="jmsConnectionFactory" jndi-name=" jms/myCF "/>
    
    <bean id="jmsQueueTemplate" 
             class="org.springframework.jms.core.JmsTemplate">
      <property name="connectionFactory">
          <ref bean="jmsConnectionFactory"/>
       </property>
       <property name="destinationResolver">
          <ref bean="jmsDestResolver"/>
       </property>
        ...
    </bean>
    
    <!-- A dynamic resolver -->
    <bean id="jmsDestResolver" class=" 
          org.springframework.jms.support.destination.DynamicDestinationResolver"/>
    
    <!-- A JNDI resolver -->
    <bean id="jmsDestResolver" 
    	class=" org.springframework.jms.support.destination.JndiDestinationResolver"/>

    在运行时,JMSTemplate 可以基于目的地的 JNDI 名称(在应用程序资源引用中配置)或通过“动态解析”来基于 WebSphere Application Server 中配置的目的地的管理名称定位目的地;例如,对于绑定到 jms/myQueue 的 JNDI 引用的 JMS myQueue 队列:

    JNDI 解析:
    jmsTemplate.send("java:comp/env/jms/myQueue", messageCreator);

    动态解析:
    jmsTemplate.send("myQueue", messageCreator);

    作为对 J2EE 消息驱动 Bean (MDB) 的替代,Spring 提供了用于异步地处理入站 JMS 消息的消息驱动 POJO 模型。仅有一个 DefaultMessageListenerContainer 类将管理从 JMS 队列到已配置的 POJO 的消息,该 POJO 必须是 javax.jms.MessageListener 实现。

    在 WebSphere Application Server 环境中,您还必须指定一个 WorkManagerTaskExecutor 类,这意味着 DefaultMessageListenerContainer 类将向服务器管理的线程池作出委托。正如上面描述过的,还应该通过 WebSphereUowTransactionManager 使用服务器的事务管理来配置 DefaultMessageListenerContainer。

    <bean id="messageListener" class="sample.ExampleMessageListener" />
    
       <bean id="msgListenerContainer"
          class="org.springframework.jms.listener.DefaultMessageListenerContainer">
          <property name="connectionFactory" ref="jmsConnectionFactory" />
          <property name="destination" ref="jmsQueue" />
          <property name="messageListener" ref="messageListener" />
          <property name="transactionManager" ref="transactionManager" />
          <property name="taskExecutor" ref="myTaskExecutor" />
       </bean>
    
       <bean id="myTaskExecutor"
          class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
          <property name="workManagerName" value="wm/default" />
       </bean>
    
       <bean id="transactionManager"
          class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
    
       <jee:jndi-lookup id="jmsConnectionFactory" jndi-name="jms/CF1" />
    
       <jee:jndi-lookup id="jmsQueue" jndi-name="jms/jmsQueue" />

    虽然可以使用此消息驱动 POJO 模型,但是在需要工作负载管理和/或高可用性的 WebSphere Application Server 配置中,建议直接使用 J2EE 消息驱动 Bean (MDB)。请注意,不支持任何其他 Spring JMS MessageListenerContainer 类型,因为它们可以启动非托管线程,而且还可能使用不应由 Java EE 环境中的应用程序调用的 JMS API。

  • 将 JPA 与 Spring 一起使用

    EJB 3.0 规范将 Java Persistence API (JPA) 定义为提供可移植持久 Java 实体的方法。WebSphere Application Server V7 和 WebSphere Application Server V6.1 EJB 3 功能包都提供了 EJB 3 和 JPA 的实现;还可以将 JPA 的 Apache OpenJPA 实现与 WebSphere Application Server V6.1 一起使用(请参见参考资料)。将 Spring 与 JPA 实现结合使用时,您应该直接使用 JPA,而不是使用 Spring 的 JPA Helper 类(在 org.springframework.orm.jpa 包中)。

    WebSphere Application Server V6.1 及更高版本支持 JPA 应用程序托管的实体管理器,该管理器可能是 JTA 或本地资源事务类型。JTA 实体管理器使用应用程序服务器的基础 JTA 事务支持,其事务划分可以使用上面描述的标准 J2EE 技术或 Spring 的声明式事务模型进行定义。

    使用 JPA 的数据访问对象 (DAO) 与 persistence.xml 打包在一起,后者为应用程序使用的 JPA EntityManager 定义持久性上下文。例如,可以按下面的方式设置用于 JTA 实体管理器(使用的数据源的 JNDI 名称为“java:comp/env/jdbc/springdb”)的 persistence.xml:

    <persistence 
       xmlns="http://java.sun.com/xml/ns/persistence"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
       http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    	<persistence-unit name="default" transaction-type="JTA">
    	<provider> org.apache.openjpa.persistence.PersistenceProviderImpl </provider>
    	<jta-data-source> java:comp/env/jdbc/springdb </jta-data-source>
    	<properties>
    		<property name="openjpa.TransactionMode" value="managed" />
    		<property name="openjpa.ConnectionFactoryMode"value="managed" />
    		<property name="openjpa.jdbc.DBDictionary" value="db2" />
    	</properties>
    	</persistence-unit>
    </persistence>

    通过将 openjpa.TransactionMode 和 openjpa.ConnectionFactoryMode 属性设置为“managed”,JPA 实体管理器将事务和连接管理委托给 WebSphere Application Server。DAO 可以使用上面描述的 Spring 声明式事务划分。

    还可以使用注释风格的 JPA EntityManager 注入。这与标准 JPA 完全相同:

    @PersistenceContext
    private EntityManager em;

    您需要以下 XML 代码将在 Spring XML 配置中启用 EntityManager 注入:

    <!-- bean post-processor for JPA annotations --> 
    <bean class=
    "org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    Spring 将在此 XML 文件中定义的 EntityManagerFactory 的基础上创建 EntityManager 。如果存在多个 EntityManagerFactory,则 Spring 将失败。使用以下方法中的一种(且仅一种)方法创建 EntityManagerFactory:

    • 使用 Spring 的基本配置
      <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
         <property name="persistenceUnitName" value="default"/>
      </bean>
    • 使用 Spring 的高级配置
      <bean id="myEmf" class=
      "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="ds"/>
      </bean>
      
      <jee:jndi-lookup 
          id="ds" 
          jndi-name="jdbc/ds" 
          cache="true" 
          expected-type="javax.sql.DataSource"
      />

    当然,通过使用 WebSphere Application Server V7 和 WebSphere Application Server V6.1 EJB 3 Feature Pack 中的纯粹 EJB 3 支持也可以获得注释和 JPA 的优点。在任一种情况下,您都可以使用 JPA API 创建 EntityManagerFactory,如下所示。建议不要将此方法用于非 EJB 3 环境,因为可能无法正确管理所创建的任何 EntityManager。但是,当您拥有 EJB 3 环境时,可以使用此方法分离 Spring 和 JPA 配置。

    <bean id="myEmf" 
       class="javax.persistence.Persistence" 
       factory-method="createEntityManagerFactory" >
      <constructor-arg type="java.lang.String" value="default"/>  
    </bean>
  • IBM JDK 6

    WebSphere Application Server V7 在 IBM JDK 6 上运行,由于已在此 JIRA 中作文档说明的 Spring 问题,无法将 IBM JDK 6 与 V2.5.5 以前的 Spring 框架一起使用。

集成和管理注意事项

  • JMX 和 MBean

    仅当 Spring JMX MBean 向 WebSphere Application Server 的容器管理器 MbeanServer 注册后,WebSphere Application Server V6.1 和更高版本才支持它。如果不指定任何服务器属性,则 MBeanExporter 将尝试自动检测运行的 MbeanServer。因此,在 WebSphere Application Server 上运行应用程序时,Spring 框架将找到容器的 MbeanServer。

    您不应使用 MBeanServerFactory 实例化 MbeanServer,然后将其注入 MbeanExporter。而且,WebSphere Application Server 不支持使用 Spring 的 ConnectorServerFactoryMBean 或 JMXConnectorServer 通过打开入站 JMX 端口将本地 MBeanServer 公开给客户端。

    WebSphere Application Server Version 6.1 以前的版本不支持 Spring JMX Mbean。

  • 在 WebSphere Application Server 中注册 Spring MBean

    当按下面的方式注册时,WebSphere Application Server MBean 将由 javax.management.ObjectName 标识:

    WebSphere:cell=99T73GDNode01Cell,name=JmxTestBean,node=99T73GDNode01,
    process=server1,type=JmxTestBeanImpl

    这意味着,如果它们被取消注册,则需要使用相同的“完全限定”名称(而不是 MBean 的简单名称属性)查找它们。最好的方法是实现 org.springframework.jmx.export.naming.ObjectNamingStrategy,它是封装 ObjectName 实例创建的接口,并且在注册 Bean 时,MBeanExporter 可以使用它获得 ObjectName。Spring Framework 论坛上提供了一个示例。可以将 ObjectNamingStrategy 实例添加到您注册的 Bean。这可以确保在卸载应用程序时正确地取消注册 MBean。

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"
       lazy-init="false">
    <property name="beans">
    	<map> <entry key="JmxTestBean" value-ref="testBean" /> </map>
    </property>
    <property name="namingStrategy" ref="websphereNamingStrategy" />
    ...
    </bean>
  • MBean ObjectName 和通知

    由于在 WebSphere Application Server 中使用的是 MBean 的完全限定 ObjectName,因此建议您完整定义该 ObjectName 以使用通知。此 JIRA 支持改为使用 Spring Bean 名称,,但是仅当您在使用相应版本的 Spring 的时候,才应该提供修复程序。

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" 
       lazy-init="false">
    	<property name="beans">
    		<map>
    		  <entry key="JmxTestBean" value-ref="testBean" />
    		</map>
    	</property>
    	<property name="namingStrategy" ref="websphereNamingStrategy" />
    	<property name="notificationListenerMappings">
    		<map>
    		  <entry key="WebSphere:cell=99T73GDNode01Cell, name=JmxTestBean,
    			node=99T73GDNode01, process=server1, type=JmxTestBeanImpl">
    			  <bean class="client.MBeanListener" />
    		  </entry>
    		</map>
    	</property>
    </bean>
  • System z 多调用/单调用限制

    由于 Spring 不允许在 MBean 描述符中指定特定于平台的字段,因此 Spring JMX 将在 WebSphere Application Server V6.1 中的多 SR 服务器上运行,但在部署选项中受限。WebSphere Application Server 缺省使用单调用策略,这样仅要求一个 MBean 实例(在一个不确定的 SR 中)就可以执行某个请求。在某些场景中这已足够,但是应用程序更可能需要能够声明多调用和单调用方法的组合,并且可能产生聚合逻辑。

  • 调度和线程池

    Spring 提供了许多可用于调度工作的 TaskExecutor 类。只有 WebSphere Application Server 支持用于异步执行工作的 Spring TaskExecutor 才是 Spring WorkManagerTaskExecutor 类,该类可正确地利用 WebSphere Application Server 托管的线程池,并向已配置的 WorkManager 作出委托。其他 TaskExecutor 实现可以启动非托管线程

    在 WebSphere Application Server 管理控制台中,可以通过导航到 Resources => Asynchronous beans => Work managers 对 WorkManager 进行设置。然后可以在 Spring 配置文件中作为 workManagerName 属性使用资源的 JNDI 名称来定义 WorkManagerTaskExecutor。下面的示例使用 WebSphere Application Server 的 DefaultWorkManager JNDI 名称或 wm/default:

    <bean id="myTaskExecutor" 
    	class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
      <property name="workManagerName" value="wm/default" />
    </bean>
  • 类加载器

    Spring 和 WebSphere Application Server 都使用多个开放源代码项目,遗憾的是,它们共有的项目版本并不总是匹配。应该将 Spring 依赖项包装为应用程序的一部分,并且应该按照下面的描述设置服务器以避免冲突。否则,类加载器可能无法为运行时或应用程序加载适当的版本。通常,这将导致异常,在日志中显示类、ClassCastExceptions 或 java.lang.VerifyErrors 的版本不匹配。

    其中一个示例是使用 Jakarta Commons Logging。要配置供应用程序使用的 Jakarta Commons Logging (JCL),或者使用不是由应用程序服务器提供的其他版本的 JCL(例如,使用应用程序代码嵌入的 JCL),将需要在 WebSphere Application Server 上进行专门的配置。有关如何配置已部署的应用程序,以使用嵌入版本的常用技术的策略,请参见集成 Jakarta Commons Logging。请密切关注支持网站,了解是否提供了有关如何在 WebSphere Application Server V6.x 产品上配置嵌入式 JCL 的更新。这仅仅是冲突的一个示例。其他示例可能包括应用程序使用 JDOM 或特定版本的 JavaMail。不支持将 WebSphere Application Server 的 JAR 文件替换为这些或具有更高版本或不同版本的其他包。

    在 WebSphere Application Server 上困扰 Spring 用户的另一个类加载器问题是 Spring 加载资源的方法。资源可以包括消息绑定之类的内容,通过类加载器层次结构和在层次结构中查找资源的各种策略,可以在非预期的位置找到使用公共名称的资源。可以使用 WebSphere Application Server 类加载器查看器来帮助解决此问题。资源与其他版本的公共库的组合可能要求应用程序将资源重命名为唯一的名称。

    James Estes 在 Spring 论坛上阐述的示例包含打包为 EAR 文件的 EJB 项目和 Web 项目。所描述的解决方案是将 spring.jar 文件同时添加到 WEB-INF/lib 和顶级 EAR 中,然后将 WEB 项目的类加载器策略设置为 PARENT LAST,以便先找到 WEB-INF/lib 中的版本。EJB 项目使用 EAR 中的版本。

设计注意事项

Spring Framework 提供的某些基础结构服务将复制由基于标准的应用程序服务器运行时提供的服务。而且,从基础 J2EE 应用程序服务器抽象出 Spring 框架基础结构必然要削弱与应用程序服务器运行时服务质量的集成,如安全性、工作负载管理和高可用性。因此,在应用程序设计过程中,必须认真考虑部署到 WebSphere Application Server 中的应用程序中的 Spring Framework 使用,以避免降低 WebSphere Application Server 提供的任何服务质量。如果没有任何其他建议,首选的方法是直接使用 WebSphere Application Server 提供的服务,以便基于开放标准开发应用程序,并确保未来部署的灵活性。

  • 非托管线程

    某些 Spring 场景可能导致创建非托管的线程。非托管线程对 WebSphere Application Server 是未知的,并且不能访问 Java EE 上下文信息。此外,它们可以在 WebSphere Application Server 不知道的情况下利用资源,在管理员无法控制其数量和资源使用的情况下存在,在发生故障时,它们还阻止应用程序服务器正常关闭或恢复资源。应用程序应该避免导致启动非托管线程的任何场景,如:

    • registerShutdownHook

      避免使用 Spring AbstractApplicationContext 或其子类之一。registerShutdownHook 是一个公共方法,它可以创建线程并将其注册到 Java 虚拟机,以便在关机时运行以关闭 ApplicationContext。应用程序可以避免这一点,方法是利用从 WebSphere 容器接收的常规生命周期通知来显式调用 ApplicationContext 上的关闭。

    • WeakReferenceMonitor

      Spring 为简化开发 EJB 组件提供了方便的类,但是请注意,这些方便的类会生成由 WeakReferenceMonitor 用来执行清除操作的非托管线程。

  • 调度

    Spring 提供(或集成)了大量的调度包,但是,只有与 WebSphere Application Server 托管的线程一起使用的 Spring 调度包才是 CommonJ WorkManager。其他包(如 quartz 和 JDK Timer)会启动非托管线程,应该避免使用。


使用 Hibernate

Hibernate 是用于 POJO 的开放源代码持久性框架,它通过 XML 配置文件提供 POJO 到关系数据库表的对象-关系映射。Hibernate 框架是应用程序调用来实现数据持久性的数据访问抽象层。此外,Hibernate 还提供了从 Java 类到数据库表(以及从 Java 数据类型到 SQL 数据类型)的映射,以及数据查询和检索功能。Hibernate 生成必需的 SQL 调用,还负责结果集处理和对象转换。

Hibernate(如 OpenJPA)实现了 Java Persistence API (JPA) 规范,此规范是 Java EE 5 的必备组成部分。(有关如何使用 Hibernate 的 developerWorks 文章,请参见参考资料。)

使用场景

以下场景描述了有关如何将 Hibernate 与 WebSphere Application Server 和 WebSphere 产品堆栈结合使用的一些可能场景。这些仅是示例场景,不应认为是推荐的场景。

  • 使用 WebSphere Application Server 数据源

    为了让 Hibernate 从 WebSphere Application Server 获取数据库连接,必须使用 Java EE(以前称为 J2EE)规范中强制规定的资源引用。这可以确保 WebSphere Application Server 能够为连接池、事务语义和隔离级别提供正确的行为。通过将 hibernate.connection.datasource 属性(在 Hibernate 配置文件中进行了定义)设置为引用在模块的部署描述符中定义的资源引用(例如 java:comp/env/jdbc/myDSRef),将 Hibernate 配置为从 WebSphere Application Server 检索数据源。例如:

    <property name="hibernate.connection.datasource">
    	java:/comp/env/jdbc/myDSRef
    </property>

    Web 应用程序的 Java EE 资源引用在 WAR 文件级别定义,这意味着容器中的所有 Servlet 和 Java 类均共享资源引用。在 EJB 模块内部,资源引用在各个 EJB 组件上定义。这意味着,如果许多 EJB 组件都使用相同的 Hibernate 配置,则每个 EJB 必须在每个 EJB 组件上定义相同的引用名称。这会导致复杂化,稍后我们将对此做进一步讨论。

    配置了数据源之后,确保 Hibernate 正常工作的下一个步骤是正确配置事务支持。

  • 事务策略配置

    为了正确地运行事务,Hibernate 需要两个重要部分的配置。第一个部分是 hibernate.transaction.factory_class,它定义事务控制,第二个部分是 hibernate.transaction.manager_lookup_class,它定义注册事务同步的机制,这样,当持久性管理器需要与数据库同步更改时,将会在事务端得到通知。对于事务控制,同时支持容器管理的配置和 Bean 管理的配置。将 Hibernate 和 WebSphere Application Server 结合使用时,必须在 Hibernate.cfg.xml 中设置以下属性:

    • 对于容器管理的事务:

      <property name="hibernate.transaction.factory_class">
      	org.hibernate.transaction.CMTTransactionFactory
      </property>
      <property name="hibernate.transaction.manager_lookup_class">
      	org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
      </property>
    • 对于 Bean 管理的事务:

      <property name="hibernate.transaction.factory_class">
      	org.hibernate.transaction.JTATransactionFactory
      </property>
      <property name="hibernate.transaction.manager_lookup_class">
      	org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
      </property>
      <property name="jta.UserTransaction">
      	java:comp/UserTransaction
      </property >

    jta.UserTransaction 属性将工厂类配置为从 WebSphere 容器获取 UserTransaction 对象实例的实例。

    WebSphere Application Server V6.x 和更高版本在 WebSphere 平台上支持 hibernate.transaction.manager_lookup_class 属性,WebSphere Business Integration Server Foundation V5.1 和更高版本也支持此属性。此属性将 Hibernate 配置为使用在 WebSphere Business Integration Server Foundation V5.1 和 WebSphere Application Server V6.0 中引入的 ExtendedJTATransaction 接口。WebSphere ExtendedJTATransaction 接口建立了一种在 Java EE 5 中通过 JTA 1.1 规范正式确立的模式。

  • 不支持的事务配置

    Hibernate 文档描述了用于在 WebSphere Application Server 版本 4 和 5 产品上运行的事务策略配置,但是这些配置使用内部 WebSphere 接口,在早期版本上不受支持。上面仅描述了受支持的 Hibernate 事务配置,如前面所述,这意味着仅在 WebSphere Business Integration Server Foundation V5.1 和 WebSphere Application Server Version 6.x 以及更高版本上支持使用 Hibernate。

  • WebSphere Application Server 环境中的 Hibernate 使用模式

    当结合使用 Hibernate 和 WebSphere Application Server 时,Hibernate 的“按请求会话”和“长时间对话”模式均可使用。客户必须选择适用于其应用程序的模式,不过我们主张使用“按请求会话”模式,因为它可以提供更好的可扩展性。

    • 多个隔离级别

      可共享的连接通过让多个资源用户能够共享现有的连接,在 WebSphere Application Server 中提供了性能改进。不过,如果可共享的连接和多个隔离级别都是必需的,则为每个连接配置定义单独的资源引用和 Hibernate 会话工厂。不能够更改共享连接的隔离级别。因此,也不可能使用 hibernate.connection.isolation 属性在可共享的连接上设置隔离级别。有关连接共享的策略和约束的详细信息,请参见在 WebSphere Application Server V5 中共享连接。(尽管本文一般适合于在 WebSphere Application Server V5 上使用的所有共享连接,但是连接共享建议仍适用于在 V6.x 上运行的 Hibernate。)

    • Web 应用程序

      可以在 HttpSession 对象中使用和存储 Hibernate 的“长时间对话”会话;不过,Hibernate 会话持有活动实例,由于可能需要将会话序列化或将其复制到其他集群成员,因此将其存储在 HttpSession 中不是可扩展的模式。最好使用 HttpSession 来存储断开连接的对象(只要它们非常小,即 10KB 到 50KB),并且在需要更新时,重新将它们与新的 Hibernate 会话关联起来。这是因为 HttpSession 最适用于书签,而不适用于缓存。在使用智能序列化改进 HttpSession 性能中讨论了如何使 HttpSession 的内存使用率降至最低。与将 HttpSession 用作缓存不同,应该考虑使用 ObjectGrid 或 DistributedObjectCache 之类的 WebSphere 数据缓存技术,这在下一部分进行介绍。

    有关高性能、可扩展应用程序的最佳实践,强烈建议您阅读 Performance Analysis for Java Websites 一书。

在本文发表之际,Hibernate 的识别集群的缓存与 WebSphere Application Server 相结合的行为还没有确定,因此,还不能确定是否支持使用该缓存,我们对此不做进一步的讨论。因此,需要分布式缓存的客户应当考虑创建使用属性 hibernate.cache.provider_class 实现 org.hibernate.cache.CacheProvider 的类,该属性将采用 WebSphere 中的两个分布式缓存实现中的一个。

  • 集成二级缓存

    Hibernate 会话表示工作单元的范围。在 Hibernate 会话的生命周期中,Session 接口管理持久性。通常,它通过保留对单个线程有效的一级缓存实例,维护它负责的映射实体类实例的可识别性或状态,从而做到这一点。该缓存在工作单元(会话)完成时消失。还可以将二级缓存配置为在 SessionFactory 的所有会话之间共享(包括在集群之间共享)。请注意,在 Hibernate 中进行缓存会导致一些需要解决的问题。第一,对于数据库的外部更改或跨集群更改,无法确保缓存的一致性(除非使用识别集群的缓存)。第二,其他层(如数据库)可能已经缓存,从而使 Hibernate 缓存的价值降至最低。在进行应用程序设计时,必须认真考虑这些问题,但是这些问题超出了本文的讨论范围。

    Hibernate 附带了几个预配置的缓存。在 Hibernate 缓存文档页中可以找到关于这些缓存的信息。对于只读数据,一个内存缓存可能就足够了。不过,当对应用程序进行集群并需要识别集群的缓存时,本地只读缓存是不够的。如果需要分布式缓存,我们建议使用 WebSphere 提供的分布式缓存实现之一。可以将它们用作 Hibernate 的二级缓存:

  • 在 WebSphere Enterprise Service Bus 和 WebSphere Process Server 中使用 Hibernate

    WebSphere Process Server 和 WebSphere Enterprise Service Bus (ESB) 将 Service Component Architecture (SCA) 和 Service Data Objects (SDO) 用作 SOA 的组装和编程模型。(请参见参考资料,了解关于 SCA 和 SDO 的更多信息。)SCA 组件不是 Java EE 组件,因此它们没有资源引用,而是依靠服务和适配器来连接系统。在构建 Java SCA 组件时,不能使用资源引用;因此,SCA 组件不能直接使用 Hibernate。

    在这种情况下,应将 Hibernate 持久性隐藏在某种 Facade 后面。有两个替代方案:

    • 创建本地 EJB 会话 Facade 以包装 Hibernate 持久性。会话 Facade 提供适配器逻辑,以便将 Hibernate 实体 POJO 映射到服务数据对象,以及进行反向映射。然后集成开发人员可以使用 EJB 导入来调用会话 Facade,并以紧密耦合方式使用对应的服务质量 (QoS) 调用它。

    • 创建 EJB Web 服务会话 Facade 以包装 Hibernate 持久性。然后集成开发人员可以使用 Web 服务导入调用实现持久性的 Web 服务。这不需要构建 POJO 到 SDO 的转换程序,因为目前 SCA 对数据类型只使用 SDO。图 1 说明了使用两种模式的业务流程,但该流程的详细信息不在本文的讨论范围之内。

    图 1. 示例业务流程
    图 1. 示例业务流程
  • WebSphere Application Server V6.1 上的 Hibernate JPA API

    Hibernate 的 JPA 支持提供 JPA 标准持久性,并且是专有 Hibernate API 的较好替代方案。Hibernate 的 JPA 实现需要基于 Java SE 5 的运行时,因此仅在 WebSphere Application Server V6.1 或更高版本上运行。在本文发表之际,Hibernate 的 JPA 支持不能在 WebSphere System z 和 iSeries 平台上运行。Hibernate 文档描述了如何使用 Hibernate 的 JPA 实现包装和部署应用程序。

  • 不可交互操作/不可移植的功能

    JPA 规范中的 3.2.4.2 部分描述了可能导致互操作性和潜在的可移植性问题的情况。这与结合使用延迟加载(即 @Basic(fetch=LAZY))和分离对象有关。将分离对象合并回会话时,JPA 将检查该对象,并使用任何更改值来更新数据存储区。不过,数据对象是简单的 POJO。在分离时,如果部分 POJO 状态没有加载,则在合并回去时可能显示为已更改。要使它正常工作,供应商必须实现特定于其运行时的序列化技术。这不是可互操作的,语义也可能不是可移植的。


产品和客户技术支持

用户合理关注的领域是对使用开放源代码的项目的支持,以及使用开放源代码对供应商支持其许可产品的影响。IBM 了解某些客户可能希望将非 IBM 的框架和 IBM WebSphere Application Server 结合使用,并且在为客户提供一些信息,以促进他们为 IBM WebSphere Application Server 创建最可靠的操作环境。IBM 考虑了客户安装的开放源代码和应用程序框架,它们或者打包为应用程序的一部分,或者作为共享库成为应用程序代码的一部分。在使用开放源代码项目时通过谨慎地利用此信息,客户可以满怀信心地使用 IBM 产品,并继续访问 IBM 产品和技术支持。如果在将这些框架与 WebSphere 产品结合使用时遇到问题,IBM 将尽力确保 WebSphere 产品不出现问题。

如果客户认真研究了本文中的建议,并理解以下几个关键点,则预期可以安全地在 IBM 产品上使用 Spring 和 Hibernate 之类的框架:

  • 客户必须确保按 WebSphere Application Server 允许的方式使用这些框架。具体来说,这意味着客户在使用内部产品接口时,不应使用框架——遗憾的是,许多开放源代码框架在未经认真配置的情况下就这样使用了。客户应避免在 WebSphere 上明确记录应避免的场景。

  • 对于开放源代码框架,客户应该确保理解并能够访问与 WebSphere Application Server 一起使用的框架的匹配源代码和二进制代码。

  • 建议客户从开放源代码社区或与开放源代码社区合作的合作伙伴那里获取框架的补救性服务。

有关 IBM 支持和策略的详细信息,请参考 IBM 支持手册WebSphere Application Server 支持声明

尽管在开放源代码环境中使用 WebSphere Application Servers 时按照本文建议的做法有助于增强您的体验,但本文并没有列出开放源代码组件影响 WebSphere Application Server 操作或其他组件操作的所有情况。使用开放源代码的用户务必检查所有组件的规范,以避免出现许可、支持和技术问题。

本文中的术语“支持”或“受支持”指示描述的用法仅限于使用 IBM 有文档记录的功能。作者尽最大努力提供关于如何配置和使用这些框架的建议,以确保其用法与有文档记录的产品行为一致,但本文不是保证,也不是 Spring 或 Hibernate 的支持声明。


结束语

Spring Framework 正在迅速普及。开发人员喜欢使用易用的接口和基于 XML 的配置加速 J2EE 开发和轻松地进行单元测试。框架本身也正在迅速发展,现在,网站上列出了许多子项目。与使用所有软件一样,确定在应用程序中使用它可以提供什么好处,以及是否具有实现相同结果的更好替代方法是非常重要的。当然,Spring 中的一些功能复制了已嵌入 WebSphere Application Server 的功能,所以将署到该服务器中的应用程序使用此额外的框架代码层是不可取的。但是,如果使用得当,您可以将 Spring 的许多易用的开发功能与 WebSphere Application Server 可靠的集成企业支持功能结合使用,以快速开发企业应用程序,并将其部署到 IBM 中行业领先的 J2EE 应用程序服务器。

Hibernate 是可以与 WebSphere Application Server 一起成功使用的多个持久性框架之一,可以提供到关系数据库中存储的实体数据的对象-关系映射(前提是足够小心地避免有问题的场景)。特别是,您必须确保使用 Hibernate 不涉及使用内部 WebSphere Application Server 接口。按照这里提供的建议,您可以避免一些常见问题,并将 Hibernate 用作部署到 WebSphere Application Server 的应用程序的持久性框架。


致谢

作者要感谢 Keys Botzum、Paul Glezen、Thomas Sandwick、Bob Conyers、Neil Laraway 和 Lucas Partridge,他们对本文提出了宝贵意见并作出了贡献。

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, Open source
ArticleID=184304
ArticleTitle=将 Spring 和 Hibernate 与 WebSphere Application Server 一起使用
publish-date=11042008