34

是否有任何可用的 Tomcat API 或配置可以告诉应用程序(可能在启动时),它在没有请求的情况下运行在哪个端口上?

想象一个场景,有两个 Web 应用程序在同一个 Tomcat 中运行,其中一个需要从另一个调用 Web 服务。我们不希望请求离开 Tomcat(如果您使用 Apache 服务器名称或绝对 URL,请求会出去然后再回来,它可以转到任何实例)然后回来。为此我知道机器的名称,但无法获取端口号。我知道我可以对这些信息进行硬编码,但我不想这样做,因为我希望我的war文件与应用程序服务器无关。

我知道如果我们有一个 HTTPServletRequest 我们可以找到它

这仅适用于 Tomcat 6,不适用于 Tomcat 7

4

12 回答 12

29

有了这个:

List<String> getEndPoints() throws MalformedObjectNameException,
        NullPointerException, UnknownHostException, AttributeNotFoundException,
        InstanceNotFoundException, MBeanException, ReflectionException {
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    QueryExp subQuery1 = Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"));
    QueryExp subQuery2 = Query.anySubString(Query.attr("protocol"), Query.value("Http11"));
    QueryExp query = Query.or(subQuery1, subQuery2);
    Set<ObjectName> objs = mbs.queryNames(new ObjectName("*:type=Connector,*"), query);
    String hostname = InetAddress.getLocalHost().getHostName();
    InetAddress[] addresses = InetAddress.getAllByName(hostname);
    ArrayList<String> endPoints = new ArrayList<String>();
    for (Iterator<ObjectName> i = objs.iterator(); i.hasNext();) {
        ObjectName obj = i.next();
        String scheme = mbs.getAttribute(obj, "scheme").toString();
        String port = obj.getKeyProperty("port");
        for (InetAddress addr : addresses) {
            if (addr.isAnyLocalAddress() || addr.isLoopbackAddress() || 
                addr.isMulticastAddress()) {
                continue;
            }
            String host = addr.getHostAddress();
            String ep = scheme + "://" + host + ":" + port;
            endPoints.add(ep);
        }
    }
    return endPoints;
}

你会得到一个这样的列表:

[http://192.168.1.22:8080]
于 2013-07-31T13:43:00.837 回答
24

对于任何对我们如何解决这个问题感兴趣的人,这里是模拟代码

Server server = ServerFactory.getServer();
        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();
                    System.out.println("HTTP Port: " + connector.getPort());
                }
            }


        }
于 2011-07-22T18:50:04.867 回答
7
public void getIpAddressAndPort() 
throws MalformedObjectNameException, NullPointerException,
            UnknownHostException {

        MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();

        Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"),
                Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));

        String host = InetAddress.getLocalHost().getHostAddress();
        String port = objectNames.iterator().next().getKeyProperty("port");

        System.out.println("IP Address of System : "+host );
        System.out.println("port of tomcat server : "+port);

    }
于 2016-08-12T09:43:03.553 回答
2

服务器端口号不存在。它可以有任意数量的端口号。所以你问的没有意义。与特定请求关联的端口号确实有意义。

于 2010-11-18T01:08:24.390 回答
1
  • 获取 Tomcat/服务器实例的 MBean/JMX 对象
  • 从那里获取虚拟服务器实例相关数据

检查http://svn-mirror.glassfish.org/glassfish-svn/tags/embedded-gfv3-prelude-b07/web/web-glue/src/main/java/com/sun/enterprise/web/WebContainer.java以供参考

然后可以通过各种协议公开 MBeanServer的内容,这些协议由协议连接器 [RMI/IIOP] 或协议适配器 [SNMP/HTTP]实现。在这种情况下,使用 SNMP 适配器将是一种更好的方法,这样可以在不知道其他应用程序服务器的确切 IP/端口的情况下放置 SNMP 陷阱

于 2010-11-18T17:43:44.057 回答
1

这些类型的服务器旨在能够侦听(几乎)任意端口,并将这些细节隐藏在通常不需要知道的包含应用程序中。

唯一的方法是自己读取配置文件访问启动服务器的命令行参数,其中配置文件可能已被覆盖。您必须对正在运行的系统有很多了解才能使其正常工作。没有办法做到便携。

即使有,在某些情况下,就像在 NAT、某些防火墙等后面一样,这根本不重要。

于 2010-11-21T20:23:55.813 回答
1

您可以使用crossContext。但我不认为这与应用服务器无关。

我将共享一个自定义类,作为通过 JNDI 在同一个 tomcat 实例中运行的应用程序的注册表,正如我在此处解释的那样。

在启动期间,通过ContextListenerSpring 容器事件或通过 Spring 容器事件,我将通过 JNDI 查找获取注册表,使用从 servletcontext.contextpath 获得的 url 添加我的 Web 应用程序实例,最后注册一个侦听器以听到其他应用程序注册自己。这是我能想到的更多的服务器不可知论。

获取端口不会与服务器无关,您应该使用上下文参数。

编辑:对不起,忘了说我所描述的是在上下文之间共享对象,但是不,除非您使用某些服务器 API(根本不知道),否则您不能不知道端口。

于 2010-10-07T23:09:59.367 回答
1
public String getPort() {
    MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
    Set<ObjectName> objectNames;
    try {
        objectNames = beanServer.queryNames(new ObjectName("*:type=ProtocolHandler,*"),
                Query.match(Query.attr("name"), Query.value("\"http-*")));
    } catch (MalformedObjectNameException e) {
        LOGGER.error("Port not defined!", e);
    }

    return objectNames.iterator().next().getKeyProperty("port");
}

public String getSecurePort() {
    MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
    Set<ObjectName> objectNames;
    try {
        objectNames = beanServer.queryNames(new ObjectName("*:type=ProtocolHandler,*"),
                Query.match(Query.attr("name"), Query.value("\"https-*")));
    } catch (MalformedObjectNameException e) {
        LOGGER.error("SecuredPort not defined!", e);
    }

    return objectNames.iterator().next().getKeyProperty("port");
}
于 2019-05-17T08:14:46.163 回答
0

以前在一个大型分布式项目中,我使用的设计是让中央服务使用中央服务的 URL(& 端口)初始化多个服务。

显然,这意味着中央服务必须维护一个服务列表(URL 和端口)来初始化。

于 2010-11-16T11:46:46.677 回答
0

我不完全确定您是否可以从您需要的环境配置中的代码访问 Tomcat 端口。您是否考虑过将 Web 服务的完整 URL 作为配置参数/设置(可能在 .properties 文件中)传递给应用程序?

这样,您就不必对端口进行硬编码并解耦您的两个应用程序,这样您就可以在技术上在外部 tomcat 上拥有 Web 服务,但仍然可以通过更改属性来访问它,从而避免重新构建代码。

于 2010-10-05T21:22:58.950 回答
0

如果要访问同一服务器实例上的应用程序,只需省略 URL 的服务器部分。您可以实现的一些示例。当前文件位于http://example.com:8080/app2/doc.html

  • xxx.html变成http://example.com:8080/app2/xxx.html
  • ../xxx.html变成http://example.com:8080/xxx.html
  • ../xxx.html变成http://example.com:8080/xxx.html
  • ../foo/xxx.html变成http://example.com:8080/foo/xxx.html
  • ../../xxx.html变成http://example.com:8080/xxx.html(没有办法超越根)
  • /xxx.html变成http://example.com:8080/xxx.html 这可能就是你要找的。
  • //other.com/xxx.htmlhttp://example.com:8080/xxx.html如果您想保留“https:”,则变得有用
于 2010-11-19T14:16:00.317 回答
-1

嗯,一个应用程序如何在没有请求的情况下在 Tomcat 中启动?也许我会在这里暂时脑死亡,但我认为在请求命中之前不会加载任何类。当然,您可以拥有独立于任何特定请求的类,但他们需要一个请求才能在某个时候将它们解雇。

于 2010-10-05T20:42:37.333 回答