使用Spring进行JMS消息传递

我碰巧看到了一篇文章,是有关使用Spring框架来简化与IBM WebSphere MQ的交互的。这篇文章是对Spring中的JMS支持的相当不错的介绍,但是有一些重要的东西它却没有提到。

  Spring作为J2EE框架的地位,与最近BEA宣布在WebLogic中对Spring提供正式支持这则消息结合起来,就会使一些开发人员认为,文章中的代码可以不加修改地用于在WebLogic上运行的J2EE应用程序(很有可能,大部分人会选择使用WebLogic startup类而不是基于文件的JDNI来映射MQ ConnectionFactory和队列到WebLogic JNDI命名空间中,或通过支持Foreign JMS提供者来映射)。

  那么,把文章中的代码用于在WebLogic上运行的J2EE应用程序又会产生什么结果呢?如预料中的一样,它确实运行了——消息被发送和交付,没有出现异常,所以乍一看一切都很正常。直到您将其用于CMT或BMT事务,比如说下面来自一个会话bean的代码:

代码:

/**
 * @ejb.bean
 *   type="Stateless"
 *   name="SpringTest"
 *   view-type="local"
 *   transaction-type="Container"
 *
 * @ejb.transaction
 *   type="RequiresNew"
 */
public class SpringTestBean implements SessionBean {
...
  /** @ejb.interface-method */
  public void sendMessage() throws Exception {
    JmsSender jmsSender = 
      (JmsSender)springContext.getBean("jmsSender");
    jmsSender.sendMesage("test");
    // rollback CMT transaction
    sessionContext.setRollbackOnly();
  }
... 
}



本来事务回滚之后,消息应该不在MQ中,但是实际情况是消息在MQ中。其原因非常简单——WebLogic需要使用特定的包装器来包装MQ ConnectionFactory对象,以确保在XA事务上下文中获取正确的资源。仅仅将对象放入WebLogic JNDI是不够的。开发人员应该通过EJB部署描述符中的resource-ref元素声明ConnectionFactory:

代码:

<resource-ref>
  <res-ref-name>myQcf</res-ref-name>
  <res-type>javax.jms.QueueConnectionFactory</res-type>
  <res-auth>Container</res-auth>
  <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
...
<resource-description>
  <res-ref-name>myQcf</res-ref-name>
  <jndi-name>mq.qcf</jndi-name>
</resource-description>
然后,在Spring上下文定义中,QueueConnectionFactory应该引用通过resource-ref映射的名字:
    <bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/myQcf"/>
    </bean>




然后,在Spring上下文定义中,QueueConnectionFactory应该引用通过resource-ref映射的名字:

代码:


<resource-ref>
  <res-ref-name>myQcf</res-ref-name>
  <res-type>javax.jms.QueueConnectionFactory</res-type>
  <res-auth>Container</res-auth>
  <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
...
<resource-description>
  <res-ref-name>myQcf</res-ref-name>
  <jndi-name>mq.qcf</jndi-name>
</resource-description>
然后,在Spring上下文定义中,QueueConnectionFactory应该引用通过resource-ref映射的名字:
    <bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/myQcf"/>
    </bean>




注意,该工厂是在java:comp/env命名空间中,而不是在JNDI全局作用域中进行查找。这将确保WebLogic所使用的将要参与全局事务的ConnectionFactory对象经过正确包装,然后上面的例子就会如预料那样运行了。

  虽然上面的例子正常运行了,但是还是有一些问题。因为现在所有使用Spring的JMS对象的操作都应该由某个正确定义了resource- ref的EJB发起。这意味着,例如,开发人员要非常小心,不要把JMSSender作为依赖注入到某个可以不作为EJB调用序列(例如,调度程序之类)的一部分而执行的类或需要访问多个ConnectionFactory的类中。另一种方法是扩展Spring的 JndiObjectFactoryBean类,支持创建所要求的包装器。这种方法的问题是,(据我所知)该包装器API还没有说明文档。

  所以,最后结论是,最好不要假设Spring会“魔法”,然后就期待一切发生,还是要经常测试,确保它真的 管用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值