apache / shenyu

Apache ShenYu is a Java native API Gateway for service proxy, protocol conversion and API governance.
https://shenyu.apache.org/
Apache License 2.0
8.44k stars 2.93k forks source link

[Question] How to get the current `external` Tomcat `port` correctly? #2872

Closed loongs-zhang closed 2 years ago

loongs-zhang commented 2 years ago

Question

After https://github.com/apache/incubator-shenyu/pull/2861 had been merged, I also want to make shenyu-client-springmvc to set port automatically. However, when the springmvc application is deployed in an external tomcat, how to correctly obtain the port number of the current Tomcat?

Here is the code:

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import java.lang.management.ManagementFactory;
import java.util.Set;

/**
 * get the port number exposed by the current tomcat
 */
public class PortUtils {

    /**
     * logger.
     */
    private static final Logger LOG = LoggerFactory.getLogger(PortUtils.class);

    private static int tomcatPort = -1;

    /**
     * get the current tomcat port number
     */
    public static Integer getPort() throws MalformedObjectNameException, ReflectionException, AttributeNotFoundException, InstanceNotFoundException, MBeanException {
        if (tomcatPort != -1) {
            return tomcatPort;
        }
        MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> objectNames = mBeanServer.queryNames(new ObjectName("*:type=Connector,*"), null);
        if (CollectionUtils.isNotEmpty(objectNames)) {
            //fixme When there are many instances of external tomcat, there may be a problem here
            for (ObjectName objectName : objectNames) {
                String protocol = String.valueOf(mBeanServer.getAttribute(objectName, "protocol"));
                String port = String.valueOf(mBeanServer.getAttribute(objectName, "port"));
                // The property name is HTTP1.1, org.apache.coyote.http11.Http11NioProtocol under linux
                if ("HTTP/1.1".equals(protocol) || "org.apache.coyote.http11.Http11NioProtocol".equals(protocol)) {
                    return tomcatPort = Integer.parseInt(port);
                }
            }
        }
        throw new IllegalStateException("failed to get the HTTP port of the current tomcat");
    }

}
loongs-zhang commented 2 years ago

Not supported when there are multiple instances of external Tomcat.