【问题标题】:Obtaining the port that Tomcat is running on from inside a Spring Boot WAR file deployed to an already running instance of Tomcat 8从部署到已运行的 Tomcat 8 实例的 Spring Boot WAR 文件中获取运行 Tomcat 的端口
【发布时间】:2015-12-14 18:53:07
【问题描述】:

我有一个 Spring Boot 应用程序,其中应用程序的每个实例都是集群中的一个节点,每个节点都需要能够与集群中的其他节点通信以共享信息。出于性能原因,这不能通过 HTTP 发生,尽管集群中每个节点的初始联系是通过 HTTP 调用。

要进行初始 HTTP 调用,实例需要能够获取其他实例正在运行的端口,以便它们可以相互注册。这意味着每个节点都需要知道其 Tomcat 实例使用的端口。

如果我部署一个包含嵌入式 Tomcat 实例的 WAR 文件,这可以正常工作。我为 EmbeddedServletContainerInitializedEvent 注册了一个 ApplicationListener 并从 EmbbededServletContainer 获取端口。

当我将 WAR 文件部署到已经运行的 Tomcat 实例时,问题就出现了。我无法找到一种方法来确定 Tomcat 实例正在哪个端口上运行,并且由于 Tomcat 实例已经在运行,因此上述事件不再触发。

有人知道如何找出正在使用的端口吗?

【问题讨论】:

  • 你有没有尝试过?这是tomcat7的帖子stackoverflow.com/questions/6833947/…你看到了吗?
  • 嗨,安。感谢您的回复。我找到了您刚才提到的答案,但当时它对我不起作用。在阅读了您的问题后,我再次尝试了一下,发现提到的代码对何时被调用很敏感。我的代码在 SpringBoot 代码完成初始化之前就已经运行了。我现在发现 ow 可以完成这项工作,这解决了我的问题。

标签: java spring tomcat spring-boot


【解决方案1】:

简单地说:你不能。 webapp 不知道它在哪个容器中运行。事实上,一个 Tomcat 可以有多个连接器并监听多个端口...

【讨论】:

  • 谢谢。是的。这正是我所期望的答案。正如我在其他回复中所说的那样,我试图弄清楚这是否可能。我们有一个使用嵌入式 Tomcat 容器进行部署的有效解决方案。不过,在这种情况下,我们在 AWS 中使用 Elastic Beanstalk 和 Docker 在负载均衡器后面进行部署,我必须使用 Describe API 和机器实例上的标签来处理 AWS 中的发现。我只是想确定这是否可能。你的回答似乎印证了我的想法。
【解决方案2】:

我知道这并不能具体回答您的问题,但是有更简单的方法可以实现集群节点发现。

作为一个明显的例子,我建议研究使用共享数据库。这已由 JGroups 实现为 JDBC_PING

【讨论】:

  • 嗨,亚历克斯,感谢您的建议。我们的共享持久层已经是 Hazelcast、Cassandra/DynamoDB 的组合。这种部署对于嵌入式 Tomcat 实例来说不是问题,但是当我们使用 Elastic Beanstalk、Docker 和 Tomcat(非嵌入式)的组合时就会出现问题。在这一点上,我正在尝试确定我是否在浪费时间尝试解决这个问题,我们应该只使用 Docker 和未嵌入的 Tomcat,因为没有它,应用程序可以完美运行。
【解决方案3】:

经过一些工作,这个问题的修复在以下问题的代码中进行了解释(感谢Ann Addicks让我再次查看它): org.apache.catalina.ServerFactory.getServer() equivalent in Tomcat 7

这段代码对它在 SpringBoot 应用程序中的调用位置非常敏感。由于 ApplicationPreparedEvent,我的初始化代码在 SpringBoot 应用程序启动的早期运行。当我第一次尝试这段代码时,我让它运行得太早以至于代码会失败。我不太清楚为什么,但我不需要那么早地进行初始化,所以我在启动时稍后将调用移至这段代码,它解决了问题。

此代码有几个注意事项需要注意:

  1. 正如joshiste 指出的那样,这只能让我获得 Tomcat 端口之一,但这就是我所需要的全部。

  2. 正如Alex 所指出的,集群确实应该由一些后端持久存储来处理,我已经在这样做了。问题在于,有时一个节点需要调用另一个节点,因为另一个节点在集群中拥有非常熟悉的知识。这是一种不寻常的情况,对整个集群的完整性至关重要。

以下方法显示了我最终是如何工作的:

private int getTomcatContainerPort() throws MalformedObjectNameException, AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
    int serverPort = 0;
    MBeanServer mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
    ObjectName name = new ObjectName("Catalina", "type", "Server");
    Server server = (Server) mBeanServer.getAttribute(name, "managedResource");
    Service[] services = server.findServices();
    for (Service service : services) {
        for (Connector connector : service.findConnectors()) {
            ProtocolHandler protocolHandler = connector.getProtocolHandler();
            if (protocolHandler instanceof Http11Protocol
                || protocolHandler instanceof Http11AprProtocol
                || protocolHandler instanceof Http11NioProtocol) {
                serverPort = connector.getPort();
                break;
            }
        }
    }
    return serverPort;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-10
    • 2018-12-05
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 2018-05-18
    • 2015-09-03
    • 1970-01-01
    相关资源
    最近更新 更多