本站首页    管理页面    写新日志    退出


«July 2025»
12345
6789101112
13141516171819
20212223242526
2728293031


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7573815
建立时间:2006年5月29日




[Spring]使用Spring进行JMS消息传递
软件技术,  电脑与网络

lhwork 发表于 2006/7/5 14:04:05

我碰巧看到了一篇文章,是有关使用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会“魔法”,然后就期待一切发生,还是要经常测试,确保它真的 管用。 评论 * 确实,没有魔法:即使在一个基于Spring的应用程序中,资源引用也需要得到正确定义,就像普通的J2EE应用程序与这些资源交互时一样。 resource-ref元素也可以在web.xml中声明,所以同样的功能也完全适用于普通的web应用程序(WAR部署单元),而不是只适用于 EJB。这是Spring应用程序直接与应用服务器的服务连接的最典型的场景:使用Spring驱动的事务,用 JtaTransactionManager作为后端,JndiObjectFactoryBean定义指向resource-ref JNDI位置(一个JDBC DataSource或一个JMS ConnectionFactory)。 发表人:juergen.hoeller,2005年10月20日,01:59 PM * 是的,也可以在WAR中使用resource-ref,而且还要更好一些,因为可以以全局级别指定resource-ref,而对于EJB,如果我没有弄错的话,是针对每个bean。 如果定义了多个ConnectionFactory,一定要小心。因为常见的实践是在不同EJB的同一个“逻辑”名下定义它们,而且它们可以调用同一个共享的组件。 发表人:maximdim,2005年10月20日,02:33 PM http://dev2dev.bea.com/blog/maximdim/archive/2005/10/jms_messaging_w.html 作者简介 Dmitri Maximovich是一位独立顾问,专长是软件设计、开发和技术培训。他具有超过12年的从业经验,而且很早就开始涉及J2EE。他的工作包括为金融业和医药业设计和开发任务关键的应用程序。


阅读全文(3280) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.328 second(s), page refreshed 144763543 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号