Computer

Spring Bootで複数ポートを設定する方法

Spring Bootのアプリケーションで、同じアプリケーションを複数のポートでリッスンさせたいという要件があり、調べてみました。

英語のサイトなどでサンプルがあったものの、Spring Boot 2.x系ですぐに使えるサンプルがなかったのでこちらで紹介しておきます。

要件、前提など

  • Spring Boot 2.x (実際に使用したのは2.1.2.RELEASE)
  • 一つのインスタンスで複数ポートをリッスンさせたい、例: 8654, 30212, 30224
  • 接続はプレーンなHTTPでSSLは必要ない

Spring Bootのポートを変更する方法

まず、Spring Bootでサーバーのポートを変更する方法を確認しておきましょう。

Spring Bootは、何も指定しないとデフォルトでポート8080が使用されます。

このポートの設定は、application.propertiesまたはapplication.ymlファイルで上書きできます。

設定ファイルで上書きする方法

application.ymlの場合

server:
  port: 8081

application.propertiesの場合

server.port=8081

コマンドラインで実行時に指定する方法

実行時のコマンドラインオプションでポートを指定することもできます。例えば

my-application.jar --server.port=8081

といった感じですね。

ランダムなポートを使用する場合

ポート番号を0にすると、ランダムな空きポートが使用されます。ローカルな開発環境やテスト時に使用されるかもしれません。

複数のポートをリッスンさせる方法

server.port のプロパティを使うとポートを変更することはできますが、複数のポートで待ち受けることはできません。

これを変更するにはコードを書く必要があります。

Spring Bootは、デフォルトでTomcatを使用するので、Tomcatに複数のコネクターを作成して、それぞれにポートを割り当てる必要があります。

以下は、その設定を行うコードです。

@Configuration
public class EmbeddedTomcatConfiguration implements WebMvcConfigurer {

    @Value("${server.port:8080}")
    private String serverPort;

    @Value("${management.port:${server.port}}")
    private String managementPort;

    @Value("${server.additionalPorts:null}")
    private String additionalPorts;

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainer() {

        return factory -> {
            Connector[] additionalConnectors = additionalConnector();
            if (additionalConnectors != null && additionalConnectors.length > 0) {
                factory.addAdditionalTomcatConnectors(additionalConnectors);
            }
        };
    }

    private Connector[] additionalConnector() {
        if (StringUtils.isEmpty(this.additionalPorts)) {
            return new Connector[0];
        }
        Set<String> defaultPorts = Sets.newHashSet(this.serverPort, this.managementPort);
        String[] ports = this.additionalPorts.split(",");
        List<Connector> result = new ArrayList<>();
        for (String port : ports) {
            if (StringUtils.hasText(port) && !"null".equalsIgnoreCase(port) && !defaultPorts.contains(port)) {
                Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
                connector.setScheme("http");
                connector.setPort(Integer.valueOf(port.trim()));
                result.add(connector);
            }
        }
        return result.toArray(new Connector[]{});
    }

}

アプリケーションの起動時にTomcatServletWebServerFactoryを受け取り、server.additionalPortsというプロパティの値に基づいてTomcatのConnectorを追加しています。

そしてapplication.ymlには以下の値を追加します。

server:
  port: 8654
  additionalPorts: 30212, 30224

3つのポートでTomcatが移動されたことがログで確認できます。

2019-04-02 15:34:05,816 [INFO ] o.a.c.h.Http11NioProtocol.log - Starting ProtocolHandler ["http-nio-8654"]
2019-04-02 15:34:05,820 [INFO ] o.a.c.h.Http11NioProtocol.log - Starting ProtocolHandler ["http-nio-30212"]
2019-04-02 15:34:05,823 [INFO ] o.a.c.h.Http11NioProtocol.log - Starting ProtocolHandler ["http-nio-30224"]
2019-04-02 15:34:05,825 [INFO ] o.s.b.w.e.t.TomcatWebServer.start - Tomcat started on port(s): 8654 (http) 30212 (http) 30224 (http) with context path ''

-Computer