我的Web应用程序侦听队列上的JMS消息并处理消息。我编写了一些要在CI上运行的测试用例,以确认是否正确接收和处理了消息。 CI构建代码并在运行测试之前将其部署到服务器。
这是服务器使用的配置。
Spring配置
<!-- JMS message listener -->
<bean id="someMessageListener" class="com.whatever.MyListener" />
<!-- Cached Connection Factory -->
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="activeMQConnectionFactory"></property>
<property name="sessionCacheSize" value="10"></property>
<property name="reconnectOnException" value="true"></property>
</bean>
<!-- Spring message listener -->
<jms:listener-container container-type="default"
connection-factory="cachedConnectionFactory" acknowledge="client"
>
<jms:listener destination="DESTINATION" ref="someMessageListener"
method="onMessage" id="jmsSomeMessageListener" />
</jms:listener-container>
MyListener
类中的代码查找JNDI数据库资源以获取sql Connection
。进一步处理JMS消息依赖于获得有效的sql连接。 Tomcat使用Resource
中的context.xml
定义来处理JNDI资源的绑定。
当我第一次在CI上运行代码时,代码工作正常。当我使用maven目标tomcat:undeploy
和tomcat:deploy
重新部署WAR时,我的消息侦听器将无法再获取数据库连接。我得到以下异常
例外
java.lang.RuntimeException:
javax.naming.NameNotFoundException:
Name [comp/env/jdbc/postgres] is not bound in this Context. Unable to find [comp].
这是查找DataSource
JNDI查找代码
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/postgres");
我怀疑由于泄漏或不当部署导致应用程序取消部署后,旧的上下文仍然存在。尝试使用ServletContextListener
方法从onDestroy()
的{{1}}正常关闭消息侦听器(jmsSomeMessageListener)没有帮助。
在调用stop()
之前停止消息监听器也无济于事。我希望重新启动监听器会强制它使用新的上下文。
为什么tomcat:undeploy
在重新部署后会变得陈旧?这只发生在侦听器上,而不发生在查找相同Context
的其他代码上。我该怎么做才能解决问题? (我甚至打开为每个CI构建重新启动服务器以暂时解决问题)
答案 0 :(得分:1)
我解决了类似的问题,我的数据库池保持打开状态,但在重新部署战争后我无法使用JNDI查找。我通过关闭连接并在取消部署战争时从JNDI取消绑定来解决了这个问题。
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyClass implements ServletContextListener
{
private String db = "foo";
@Override
public void contextDestroyed(ServletContextEvent sce)
{
PGPoolingDataSource connectionPool =
(PGPoolingDataSource)new InitialContext().lookup(db);
if(connectionPool != null)
{
connectionPool.close();
new InitialContext().unbind(db);
}
}
}
您还需要在web.xml中添加一个块,将您的类注册为侦听器:
<listener>
<listener-class>com.foo.bar.MyClass</listener-class>
</listener>