问题:
我的一个 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 连接。 JNDI 资源的绑定(bind)由 tomcat 使用 context.xml
中的 Resource
定义来处理。
当我第一次在 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");
我尝试解决的问题:
我怀疑即使在应用程序由于泄漏或不正确的取消部署而取消部署之后,旧的上下文仍然存在。尝试使用 stop()
方法从 ServletContextListener
的 onDestroy()
正常关闭消息监听器 (jmsSomeMessageListener) 没有帮助。
在调用 tomcat:undeploy
之前停止消息监听器也无济于事。我希望重新启动监听器会强制它使用新的上下文。
问题:
为什么 Context
在重新部署后变得陈旧?这只发生在监听器上,而不发生在查找相同 Context
的其他代码上。我该怎么做才能解决这个问题? (我什至愿意为每个 CI 构建重新启动服务器以暂时解决问题)
最佳答案
我解决了一个类似的问题,我的数据库池保持打开状态,但在重新部署我的 war 后我无法使用 JNDI 查找它。我通过在取消部署 war 时关闭连接并从 JNDI 解除绑定(bind)来解决这个问题。
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 中添加一个 block ,将您的类注册为监听器:
<listener>
<listener-class>com.foo.bar.MyClass</listener-class>
</listener>
关于java - 无法在重新部署时查找 JNDI 资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21827729/