4

Using spring-boot and jetty, I'd like to be able to configure my application to listen on additional ports, which are programmatically added at runtime (+ removed?).

What I've tried:

I've followed this tutorial, which allows me to listen on multiple ports. This works perfectly, but unfortunately only works at startup only.

I've tried @Autowiring a org.eclipse.jetty.server.Server class into a service, so that I can add connectors - I got the error No qualifying bean of type [org.eclipse.jetty.server.Server] found ...

build.gradle (dependencies

buildscript {
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.6.RELEASE")
    }
}

apply plugin: 'spring-boot'

...

compile("org.springframework.boot:spring-boot-starter-web") {
    exclude module: "spring-boot-starter-tomcat"
}
compile "org.springframework.boot:spring-boot-starter-jetty"
compile "org.eclipse.jetty:jetty-proxy:9.2.17.v20160517"

...

Not sure what to try from here...

Nick Grealy
  • 24,216
  • 9
  • 104
  • 119

1 Answers1

5

You can get hold of the Jetty Server from Boot's JettyEmbeddedServletContainer which is available from the EmbeddedWebApplicationContext. Once you've got hold of the Server you can then add new connectors to it using Jetty's API.

Here's an example that adds a new connector in response to the ApplicationReadyEvent being published:

@Bean
public JettyCustomizer jettyCustomizer(EmbeddedWebApplicationContext context) {
    return new JettyCustomizer(
            (JettyEmbeddedServletContainer) context.getEmbeddedServletContainer());
}

static class JettyCustomizer implements ApplicationListener<ApplicationReadyEvent> {

    private final JettyEmbeddedServletContainer container;

    JettyCustomizer(JettyEmbeddedServletContainer container) {
        this.container = container;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        Server server = this.container.getServer();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8081);
        server.addConnector(connector);
        try {
            connector.start();
        }
        catch (Exception ex) {
            throw new IllegalStateException("Failed to start connector", ex);
        }
    }
}

You should see in the logs the default connector starting on port 8080 and then the second connector starting on 8081:

2016-08-16 10:28:57.476  INFO 71330 --- [           main] o.e.jetty.server.AbstractConnector       : Started ServerConnector@64bc21ac{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2016-08-16 10:28:57.478  INFO 71330 --- [           main] .s.b.c.e.j.JettyEmbeddedServletContainer : Jetty started on port(s) 8080 (http/1.1)
2016-08-16 10:28:57.482  INFO 71330 --- [           main] o.e.jetty.server.AbstractConnector       : Started ServerConnector@664a9613{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}
2016-08-16 10:28:57.483  INFO 71330 --- [           main] sample.jetty.SampleJettyApplication      : Started SampleJettyApplication in 1.838 seconds (JVM running for 2.132)
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • I have a similar problem can you help? https://stackoverflow.com/questions/57491231/spring-boot-how-to-dynamically-add-new-tomcat-connector – Sapnesh Naik Aug 23 '19 at 15:39
  • Hi, do you know which dependency to add to get JettyEmbeddedServletContainer? The spring-boot-starter-jetty artifact does not provide access to this class, and can't find anything on maven central. Thanks. – Tomas Antos Oct 13 '22 at 13:26
  • @TomasAntos this answer was written in the days of Spring Boot 1.x. In 2.x, you can use `JettyWebServer` which can be retrieved from `org.springframework.boot.web.context.WebServerApplicationContext.getWebServer()` – Andy Wilkinson Oct 14 '22 at 13:19