akourt
akourt

Reputation: 5563

Spring Boot 2 programmatic configuration of Embedded Servlet Container

I'm attempting to configure the embedded Tomcat provided by Spring Boot 2, my main goal being to have multiple connectors based on various deployment models.

For this I like to have the following setup in place:

So far regarding the second case I think I have been able to put the configuration in place to do so I created the following configuration class:

@Configuration
public class EmbeddedWebServerConfiguration {

    @Value("${server.port}")
    private int httpPort;

    @Value("${server.secure.port}")
    private int httpsPort;

    @Value("${server.uses.ssl}")
    private boolean usesSSL;

    @Value("${server.uses.ajp}")
    private boolean usesAjp;

    @Value("${server.ajp.port}")
    private int ajpPort;

    @Bean
    public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {

        @Override
        protected void postProcessContext(Context context) {
        SecurityConstraint securityConstraint = new SecurityConstraint();
        securityConstraint.setUserConstraint("CONFIDENTIAL");
        SecurityCollection securityCollection = new SecurityCollection();
        securityCollection.addPattern("/*");
        securityConstraint.addCollection(securityCollection);
        context.addConstraint(securityConstraint);
        }

    };

    if (usesSSL) {
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
    }

    if (usesAjp) {
        tomcat.addAdditionalTomcatConnectors(ajpConnector());
    }

    return tomcat;
    }

    private Connector redirectConnector() {
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    connector.setScheme("http");
    connector.setPort(httpPort);
    connector.setSecure(false);
    connector.setRedirectPort(httpsPort);

    return connector;
    }

    private Connector ajpConnector() {
        Connector connector = new Connector("AJP/1.3");
        connector.setScheme("http");
        connector.setPort(ajpPort);
        connector.setSecure(false);

        return connector;
    }

}

So based on the above, I have the following question:

Is there any way to have Spring omit the creation of it's default connector? I have tried looking around and on their documentation but I have not found anything helpful. Since I'm launching an AJP connector (added as an additional one) I do not want the default HTTP one to be in place.

Furthermore, when I attempt to create the redirect connector to handle HTTPS requests, my application won't start due to same port binding (the default connector listens on the same port as the redirect one).

This setup was easy enough to do on pre-2.0 Spring boot versions but for some reason it's not that easy with the new changes.

Does anyone have any solutions on how to do this? I would like to have overall control and programmatically configure anything.

Upvotes: 1

Views: 2864

Answers (1)

Kris
Kris

Reputation: 14458

I just ran into the same issue and couldn't find a solution online.

Eventually I came up with the following which forces the creation of an AJP connector only if server.tomcat.ajp.enabled is set to true, otherwise a normal http connector is created.

@SpringBootApplication
public class MyApplication {

    @Value("${server.tomcat.ajp.port}")
    int ajpPort;

    @Value("${server.tomcat.ajp.enabled}")
    boolean tomcatAjpEnabled;

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        if (tomcatAjpEnabled) {
            log.info("AJP Enabled on port {}", ajpPort);
            factory.setProtocol("AJP/1.3");

            factory.addConnectorCustomizers(connector -> {
                connector.setPort(ajpPort);
            });
        } // else create default http connector as per usual

        return factory;
    }
}

Upvotes: 2

Related Questions