Tomcat 的 WebSphere MQ 连接池
WebSphere MQ connection pooling with Tomcat
Tomcat有内置的JDBC连接池,可惜没有内置的JMS连接池。
我们正在将遗留 Tomcat Web 应用程序从 WebSphere MQ 版本 6 迁移到版本 7。
不幸的是,连接池已在 WebSphere MQ 7 中删除,如下所述:http://www-01.ibm.com/support/docview.wss?uid=swg21665128
现在Tomcat只用下面的代码配置MQ,怕运行出问题:
<Resource name="jms/XXXQCF" auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
我们担心的原因是,这在使用 MQ 7 时不会使用池化 JMS 提供程序。有关详细信息,另请参阅 http://activemq.apache.org/jmstemplate-gotchas.html
我们看到的替代解决方案是:
1) Atomikos 的使用
Atomikos 有一个 com.atomikos.jms.AtomikosConnectionFactoryBean 可以用来代替 MQQueueConnectionFactory
但是当我们不需要 XA
时,使用 XA 事务管理器是一个巨大的开销
2) 使用 Spring 的 CachingConnectionFactory
看起来是个不错的解决方案,但遗憾的是我们的遗留应用程序不使用 Spring。
所以我们假设使用 CachingConnectionFactory 需要付出很多努力。
3) 使用 Apache 共享池
看起来也很有前途,但是为 JMS 正确实施它需要一些良好的 JMS 知识
我们的问题:
- 是否有可用于包装 MQQueueConnectionFactory 并将连接、会话、生产者和消费者汇集在一起的 JMS 提供者?
- 有没有人成功实施了我们上面概述的替代解决方案之一?
我想你已经知道答案了。
选项 1:使用 Java EE 应用程序服务器。这有内置的 JMS 池。
选项 2:如果这是一个执行单一作业的简单应用程序(例如放入一个带有 fire and forget 类型的队列),您可以连接到 JMS 提供程序 (qmgr) 并在servlet_init 方法。这意味着遗留代码需要更新。由于 JMS 重新连接属性不会启动重新连接(就我的经验而言),您还需要在出现问题时处理重新连接。
选项 3:当应用程序碰巧比选项 2 复杂一点时,我选择了 Spring 的 CachingConnectionFactory。我有使用 JMSTemplate 的应用程序,有些则没有。
正如 Umapathy 在选项 3 中提出的那样,我们现在选择了使用 Spring 的 CachingConnectionFactory 的方法,即使对于非 Spring 应用程序,它也能很好地工作。您需要做的就是将 Spring Jar 添加到类路径中,并使用 CachingConnectionFactory 包装 MQQueueConnectionFactory。
我们选择创建自己的 Tomcat QueueConnectionFactoryFactory,它使我们能够完全保持原始应用程序代码不变,您只需从 Tomcat 配置文件(如图所示)替换原始 MQ 连接工厂上面的问题)具有以下 XML 定义:
<Resource name="jms/XXXQCF" auth="Container"
type="org.springframework.jms.connection.CachingConnectionFactory"
factory="at.rsf4j.core.utilities.RSFCachingMQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
这是 RSFCachingMQQueueConnectionFactoryFactory 的(简化)代码(没有错误检查):
public class RSFCachingMQQueueConnectionFactoryFactory implements ObjectFactory{
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?,?> environment)
throws NamingException {
Reference ref = (Reference) obj;
String beanClassName = ref.getClassName();
Class<?> beanClass = Class.forName(beanClassName);
if (CachingConnectionFactory.class.isAssignableFrom(beanClass)){
MQQueueConnectionFactoryFactory cff = new MQQueueConnectionFactoryFactory();
Reference mqReference = new Reference(
MQQueueConnectionFactory.class.getName());
Enumeration<RefAddr> allAddrs = ref.getAll();
while (allAddrs.hasMoreElements()){
mqReference.add(allAddrs.nextElement());
}
MQQueueConnectionFactory cf = (MQQueueConnectionFactory)cff.getObjectInstance(mqReference, name, nameCtx, environment);
CachingConnectionFactory ccf = (CachingConnectionFactory)beanClass.newInstance();
ccf.setTargetConnectionFactory(cf);
return ccf;
}
}
Tomcat有内置的JDBC连接池,可惜没有内置的JMS连接池。
我们正在将遗留 Tomcat Web 应用程序从 WebSphere MQ 版本 6 迁移到版本 7。 不幸的是,连接池已在 WebSphere MQ 7 中删除,如下所述:http://www-01.ibm.com/support/docview.wss?uid=swg21665128
现在Tomcat只用下面的代码配置MQ,怕运行出问题:
<Resource name="jms/XXXQCF" auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
我们担心的原因是,这在使用 MQ 7 时不会使用池化 JMS 提供程序。有关详细信息,另请参阅 http://activemq.apache.org/jmstemplate-gotchas.html
我们看到的替代解决方案是:
1) Atomikos 的使用
Atomikos 有一个 com.atomikos.jms.AtomikosConnectionFactoryBean 可以用来代替 MQQueueConnectionFactory 但是当我们不需要 XA
时,使用 XA 事务管理器是一个巨大的开销2) 使用 Spring 的 CachingConnectionFactory
看起来是个不错的解决方案,但遗憾的是我们的遗留应用程序不使用 Spring。 所以我们假设使用 CachingConnectionFactory 需要付出很多努力。
3) 使用 Apache 共享池
看起来也很有前途,但是为 JMS 正确实施它需要一些良好的 JMS 知识
我们的问题:
- 是否有可用于包装 MQQueueConnectionFactory 并将连接、会话、生产者和消费者汇集在一起的 JMS 提供者?
- 有没有人成功实施了我们上面概述的替代解决方案之一?
我想你已经知道答案了。
选项 1:使用 Java EE 应用程序服务器。这有内置的 JMS 池。
选项 2:如果这是一个执行单一作业的简单应用程序(例如放入一个带有 fire and forget 类型的队列),您可以连接到 JMS 提供程序 (qmgr) 并在servlet_init 方法。这意味着遗留代码需要更新。由于 JMS 重新连接属性不会启动重新连接(就我的经验而言),您还需要在出现问题时处理重新连接。
选项 3:当应用程序碰巧比选项 2 复杂一点时,我选择了 Spring 的 CachingConnectionFactory。我有使用 JMSTemplate 的应用程序,有些则没有。
正如 Umapathy 在选项 3 中提出的那样,我们现在选择了使用 Spring 的 CachingConnectionFactory 的方法,即使对于非 Spring 应用程序,它也能很好地工作。您需要做的就是将 Spring Jar 添加到类路径中,并使用 CachingConnectionFactory 包装 MQQueueConnectionFactory。
我们选择创建自己的 Tomcat QueueConnectionFactoryFactory,它使我们能够完全保持原始应用程序代码不变,您只需从 Tomcat 配置文件(如图所示)替换原始 MQ 连接工厂上面的问题)具有以下 XML 定义:
<Resource name="jms/XXXQCF" auth="Container"
type="org.springframework.jms.connection.CachingConnectionFactory"
factory="at.rsf4j.core.utilities.RSFCachingMQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
这是 RSFCachingMQQueueConnectionFactoryFactory 的(简化)代码(没有错误检查):
public class RSFCachingMQQueueConnectionFactoryFactory implements ObjectFactory{
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?,?> environment)
throws NamingException {
Reference ref = (Reference) obj;
String beanClassName = ref.getClassName();
Class<?> beanClass = Class.forName(beanClassName);
if (CachingConnectionFactory.class.isAssignableFrom(beanClass)){
MQQueueConnectionFactoryFactory cff = new MQQueueConnectionFactoryFactory();
Reference mqReference = new Reference(
MQQueueConnectionFactory.class.getName());
Enumeration<RefAddr> allAddrs = ref.getAll();
while (allAddrs.hasMoreElements()){
mqReference.add(allAddrs.nextElement());
}
MQQueueConnectionFactory cf = (MQQueueConnectionFactory)cff.getObjectInstance(mqReference, name, nameCtx, environment);
CachingConnectionFactory ccf = (CachingConnectionFactory)beanClass.newInstance();
ccf.setTargetConnectionFactory(cf);
return ccf;
}
}