Spring Boot服务器端口范围设置

4

是否可以在Spring Boot应用程序的application.yml文件中设置服务器端口的可接受范围。

我已经将server.port设置为0,以获取自动分配的端口而不是硬编码的端口。

我们的网络运营人员希望限制此端口分配的可用范围。

有任何想法吗?

6个回答

4

跟随user1289300和Dave Syer的建议,我制定了一个解决方案。将其作为配置提供,从application.yml文件中读取服务器部分。我提供了一个端口范围min和max可供选择。再次感谢。

@Configuration
@ConfigurationProperties("server")
public class EmbeddedServletConfiguration{

/*
    Added EmbeddedServletContainer as Tomcat currently. Need to change in future if  EmbeddedServletContainer get changed
 */
private final int MIN_PORT = 1100;
private final int MAX_PORT = 65535;
/**
 * this is the read port from the applcation.yml file
 */
private int port;
/**
 * this is the min port number that can be selected and is filled in from the application yml fil if it exists
 */
private int maxPort = MIN_PORT;

/**
 * this is the max port number that can be selected and is filled
 */
private int minPort = MAX_PORT;

/**
 * Added EmbeddedServletContainer as Tomcat currently. Need to change in future if  EmbeddedServletContainer get changed
 *
 * @return the container factory
 */
@Bean
public EmbeddedServletContainerFactory servletContainer() {
    return new TomcatEmbeddedServletContainerFactory();
}

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            // this only applies if someone has requested automatic port assignment
            if (port == 0) {
                // make sure the ports are correct and min > max
                validatePorts();
                int port = SocketUtils.findAvailableTcpPort(minPort, maxPort);
                container.setPort(port);
            }
           container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/404"));
           container.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN, "/403"));

        }
    };
}

/**
 * validate the port choices
 * - the ports must be sensible numbers and within the alowable range and we fix them if not
 * - the max port must be greater than the min port and we set it if not
 */
 private void validatePorts() {
     if (minPort < MIN_PORT || minPort > MAX_PORT - 1) {
         minPort = MIN_PORT;
     }

     if (maxPort < MIN_PORT + 1 || maxPort > MAX_PORT) {
         maxPort = MAX_PORT;
     }

     if (minPort > maxPort) {
         maxPort = minPort + 1;
     }
 }

}

3

只需实现EmbeddedServletContainerCustomizer即可。

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-programmatic-embedded-container-customization

当然,您可以对下面的public static boolean available(int port)进行改进,以检查端口的可用性,因为有些端口虽然可用,但有时会被拒绝,例如1024端口是操作系统相关的,而且范围可能在某些属性文件中读取,但Spring不支持,在加载上下文之前设置了范围,但这不应该成为问题。我将所有内容放在一个文件中以展示方法,而不是让其看起来很漂亮。

@Configuration
@ComponentScan
@EnableAutoConfiguration


public class DemoApplication {

    private static final int MIN_PORT = 1100; // to by set according to your
    private static final int MAX_PORT = 9000; // needs or uploaded from
    public static int myPort; // properties whatever suits you

    public static void main(String[] args) {

    int availablePort = MIN_PORT;
    for (availablePort=MIN_PORT; availablePort < MAX_PORT; availablePort++) {
        if (available(availablePort)) {

            break;
        }
    }
    if (availablePort == MIN_PORT && !available(availablePort)) {
        throw new IllegalArgumentException("Cant start container for port: " + myPort);

    }
    DemoApplication.myPort = availablePort;

    SpringApplication.run(DemoApplication.class, args);
}

    public static boolean available(int port) {
        System.out.println("TRY PORT " + port);
        // if you have some range for denied ports you can also check it
        // here just add proper checking and return 
        // false if port checked within that range
        ServerSocket ss = null;
        DatagramSocket ds = null;
        try {
            ss = new ServerSocket(port);
            ss.setReuseAddress(true);
            ds = new DatagramSocket(port);
            ds.setReuseAddress(true);
            return true;
        } catch (IOException e) {
        } finally {
            if (ds != null) {
                ds.close();
            }

            if (ss != null) {
                try {
                    ss.close();
                } catch (IOException e) {
                    /* should not be thrown */
                }
            }
        }

        return false;
    }

}

而这是最重要的部分:

@Component
class CustomizationBean implements EmbeddedServletContainerCustomizer {

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {

        container.setPort(DemoApplication.myPort);

    }

}

3
如果您喜欢这个普遍的想法,Spring有一个SocketUtils可以完成大部分工作。 - Dave Syer
谢谢,好东西,我不知道,但是没有一种方法考虑排除范围,只有最大值和最小值,将其添加到SocketUtils中是否合适或应该在外部完成? - mariubog

2

配置的最简单方式是在application.properties文件中使用以下内容。这里将8084作为最小范围,8100作为最大范围。

server.port=${random.int[8084,8100]}

0

我们在Spring Boot 1.5.9中使用EmbeddedServletContainerCustomizer完成了这个操作,代码如下:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return (container -> {
        try {

            // use defaults if we can't talk to config server
            Integer minPort = env.getProperty("minPort")!=null ? Integer.parseInt(env.getProperty("minPort")) : 7500;
            Integer maxPort = env.getProperty("maxPort")!=null ? Integer.parseInt(env.getProperty("maxPort")) : 9500;
            int port = SocketUtils.findAvailableTcpPort(minPort,maxPort);
            System.getProperties().put("server.port", port);
            container.setPort(port);
        } catch (Exception e) {
            log.error("Error occured while reading the min & max port form properties : " + e);
            throw new ProductServiceException(e);
        }

    });
}

然而,在Spring Boot 2.0.0.M7中似乎不可能实现这一点,我们正在寻找替代方法。


0

好的,Spring Boot 的开发人员说 SocketUtils.findAvailableTcpPort 在生产环境中不够稳定,这使得这里提供的所有解决方案都失效了。 - Christian

0
使用这个解决方案,应用程序会选择自己的端口。我不明白为什么它会得到“-1”,因为它运行得很完美。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.SocketUtils;    

@Configuration

   class PortRangeCustomizerBean implements EmbeddedServletContainerCustomizer 
{

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Value("${spring.port.range.min}")
private int MIN_PORT;

@Value("${spring.port.range.max}")
private int MAX_PORT;

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
    int port = SocketUtils.findAvailableTcpPort(MIN_PORT, MAX_PORT);
    logger.info("Started with PORT:\t " + port);
    container.setPort(port);
}

}


1
请解释一下你的解决方案。 - zuluk
使用这个解决方案后,应用程序会选择自己的端口。我不明白为什么它会得到“-1”,因为它运行得很完美。 - Rahmspinat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接