java - 无法在重新部署时查找 JNDI 资源

标签 java spring maven tomcat spring-jms

问题:

我的一个 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:undeploytomcat: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() 方法从 ServletContextListeneronDestroy() 正常关闭消息监听器 (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/

相关文章:

java - 如何按升序对文件名进行排序?

java - 如何使用 Cypher 返回节点的所有属性及其名称和值

java - 将 XML 转换为嵌套 map 的 Map

java - IntelliJ JUnit5 类未找到错误

java - NoClassDefFoundError 当 Maven 测试范围的依赖覆盖传递编译范围的依赖

java - 如何测试MultiChoiceItems android对话框

java - Jackson Databind ObjectMapper ConvertValue 与自定义映射实现

java - 在多线程 RMI 架构中使用 JPA

spring - 调用 spring 授权服务器 OAuth2 REST 端点

java - 无法运行第一个 Web 应用程序 Tomcat + Intellij