1
votes

I am looking to override the default EmbeddedServletContainerFactory as documented here in order to set up SSL. The old docs (from RC1 days) said to override the Customizer and that worked great until I upgraded today, changed the implementation to follow the new convention.

@Configuration
public class ContainerConfig {

@Bean
public EmbeddedServletContainerFactory servletContainer() {
  TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
  factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

  @Override
  public void customize(Connector connector) {

    connector.setPort(8443);
    connector.setSecure(true);
    connector.setScheme("https");
    connector.setAttribute("keyAlias", "tomcat");
    connector.setAttribute("keystorePass", "changeit");
    try {
      connector.setAttribute("keystoreFile", ResourceUtils.getFile("src/ssl/tomcat.keystore").getAbsolutePath());
    } catch (FileNotFoundException e) {
      throw new IllegalStateException("Cannot load keystore", e);
    }
      connector.setAttribute("clientAuth", "false");
      connector.setAttribute("sslProtocol", "TLS");
      connector.setAttribute("SSLEnabled", true);
    }

  });

  factory.setSessionTimeout(10, TimeUnit.MINUTES);

  return factory;
}

The source code in Boot (EmbeddedServletContainerAutoConfiguration) indicates that if it does find my bean, it will not register the default:

@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)

However it appears to register anyhow. Does anybody else have this working? Here is the stack:

Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to multiple EmbeddedServletContainerFactory beans : servletContainer,tomcatEmbeddedServletContainerFactory at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:135) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:619) at org.springframework.boot.SpringApplication.run(SpringApplication.java:306) at org.springframework.boot.SpringApplication.run(SpringApplication.java:880) at org.springframework.boot.SpringApplication.run(SpringApplication.java:869) at at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to multiple EmbeddedServletContainerFactory beans : servletContainer,tomcatEmbeddedServletContainerFactory at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:190) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:158) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132) ... 12 more

I have created a GitHub repo that mashes up the Tomcat and Websocket samples from the Spring Boot project, and applies this configuration.

1
That should work (and the link to the docs is up to date, although it is a different pattern to the one you implemented, since it doesn't actually create a @Bean of type EmbeddedServletContainerFactory). Can you share a project? - Dave Syer
Thanks for responding Dave, I can reproduce by putting together the tomcat and websockets samples - as soon as spring-boot-starter-websocket is a dependency this happens, probably because of some auto-config related to web sockets and the container. I can post my mashup of the two samples if that helps. - hoserdude
It is indeed the WebSocketAutoConfiguration that is the culprit, it looks like detecting existing TomcatEmbeddedServletContainerFactory beans prior to creating one in this class might be the trick, I will experiment and put a pull request in if it works. - hoserdude

1 Answers

2
votes

This is a (sort of) bug (https://github.com/spring-projects/spring-boot/issues/479). Fixed now. Workaround is to use EmbeddedServletContainerCustomizer instead of EmbeddedServletContainerFactory (like in the docs link in the original question).