10 March 2015

The Spring Boot documentation and sample applications contain good information and examples of how to use Jetty in a Spring Boot application instead of the default embedded Apache Tomcat server. However, the documentation and examples do not really address how to customize Jetty as in depth as the Tomcat examples. Recently, I found the need to make a Spring Boot application using Jetty listen on multiple ports for incoming HTTP traffic. While this is not necessarily a normal use case, it does come up often, especially when the need to listen for both HTTP and HTTPS traffic is a requirement. In a previous post, I showed how to customize the embedded Jetty server in order to change the size of the thread pool used for incoming connections. Just like the approach outlined in that post, the way to configure the embedded Jetty server in your Spring Boot application to listen to multiple ports is very similar:

@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory(
        @Value("${server.port:8080}") final String mainPort,
        @Value("#{'${server.secondary.ports}'.split(',')}") final List<String> secondaryPorts) {

    final JettyEmbeddedServletContainerFactory factory =  new JettyEmbeddedServletContainerFactory(Integer.valueOf(mainPort));

    // Add customized Jetty configuration with non blocking connection handler
    factory.addServerCustomizers(new JettyServerCustomizer() {
        @Override
        public void customize(final Server server) {
            // Register an additional connector for each secondary port.
            for(final String secondaryPort : secondaryPorts) {
                final NetworkTrafficServerConnector connector = new NetworkTrafficServerConnector(server);
                connector.setPort(Integer.valueOf(secondaryPort));
                server.addConnector(connector);
            }

            // Additional configuration
        }
    });
    return factory;
}

The example above uses the Spring Boot provided JettyServerCustomizer to register additional NetworkTrafficServerConnector instances for each secondary port provided in the application’s configuration. Additionally, the server.port Spring Boot property is still used for the main application port and is passed to the Spring Boot JettyEmbeddedServletContainerFactory, just as it would be if you simply included the appropriate starter library and set the property, per the documentation. Finally, the application configuration contains the following configuration to make it all work:

server:
  port: "8000"
  secondary:
    ports: "8082,8083,8084"

When the application starts up, you can confirm that it is indeed listening on the multiple ports by looking for the following in the output:

2015-03-09 15:13:35.483  INFO 1416 --- [           main] o.eclipse.jetty.server.ServerConnector   : Started ServerConnector@121ee28d{HTTP/1.1}{0.0.0.0:8080}
2015-03-09 15:13:35.483  INFO 1416 --- [           main] o.e.j.s.NetworkTrafficServerConnector    : Started NetworkTrafficServerConnector@36d64b9{HTTP/1.1}{0.0.0.0:8082}
2015-03-09 15:13:35.487  INFO 1416 --- [           main] o.e.j.s.NetworkTrafficServerConnector    : Started NetworkTrafficServerConnector@e51235{HTTP/1.1}{0.0.0.0:8083}
2015-03-09 15:13:35.488  INFO 1416 --- [           main] o.e.j.s.NetworkTrafficServerConnector    : Started NetworkTrafficServerConnector@3f0e5608{HTTP/1.1}{0.0.0.0:8084}
2015-03-09 15:13:35.489  INFO 1416 --- [           main] .s.b.c.e.j.JettyEmbeddedServletContainer : Jetty started on port(s) 8080 (http/1.1), 8082 (http/1.1), 8083 (http/1.1), 8084 (http/1.1)
2015-03-09 15:13:35.491  INFO 1416 --- [           main] com.test.Application                     : Started Application in 5.346 seconds (JVM running for 12.321)

comments powered by Disqus