How would you add a second Tomcat connector (e.g. a plain-HTTP management port alongside HTTPS) using a customizer?
answer
- addAdditionalTomcatConnectors(Connector...) = extra listener
- addConnectorCustomizers = tweak primary connector
- target TomcatServletWebServerFactory concretely
- no property for a 2nd connector -> must use customizer
- Tomcat-specific: won't run under Jetty/Undertow
basics
~10 sWrite a WebServerFactoryCustomizer<TomcatServletWebServerFactory>, build a Tomcat Connector (new Connector(...), set its port/protocol), and call factory.addAdditionalTomcatConnectors(connector). The factory's own connector stays the primary; extras are added on top.
solid answer
~40 sTomcat's factory exposes addAdditionalTomcatConnectors(Connector...) for exactly this. Target the concrete type: WebServerFactoryCustomizer<TomcatServletWebServerFactory>. Construct an org.apache.catalina.connector.Connector, set its scheme, port, and secure flag, then pass it to addAdditionalTomcatConnectors. The primary connector (bound to server.port) remains; the extra one is an additional listener — a common pattern for exposing a non-TLS management/health port next to a TLS main port, or an AJP connector. This is genuinely programmatic — there's no server.* property to add a second connector — which is the canonical justification for using a customizer over properties. For finer per-connector tweaks (timeouts, max-connections) on the primary connector you'd instead use addConnectorCustomizers(TomcatConnectorCustomizer...). This is Tomcat-specific; switching to Jetty/Undertow requires their own factory APIs.
code
java · 22 linesimport org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
class ManagementPortCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// Primary connector stays on server.port; add a plain-HTTP admin listener.
Connector admin = new Connector("org.apache.coyote.http11.Http11NioProtocol");
admin.setScheme("http");
admin.setPort(8081);
admin.setSecure(false);
factory.addAdditionalTomcatConnectors(admin);
// Also tweak the PRIMARY connector without replacing it:
factory.addConnectorCustomizers(c -> c.setProperty("maxConnections", "200"));
}
}go deeper
Not expected — this is advanced container config.
Should recognize that extra connectors require code, not properties, even if unsure of the exact API.
Should name addAdditionalTomcatConnectors, target the Tomcat factory type, and distinguish it from addConnectorCustomizers.
Should also weigh portability (Tomcat-specific), security of an extra management port, and where this pattern fits versus a reverse proxy.
## Why this needs a customizer Spring Boot's `server.*` properties configure **one** connector — the primary listener on `server.port`. There is **no property** to add a *second* connector. Adding another listener (a common need: a plaintext HTTP management/health port next to a TLS-secured application port, or an AJP connector behind a reverse proxy) is a textbook case for `WebServerFactoryCustomizer`. ## The Tomcat-specific factory The default servlet factory is `org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory`. It exposes Tomcat-only hooks: - `addAdditionalTomcatConnectors(Connector...)` — register extra `org.apache.catalina.connector.Connector` instances beyond the primary. - `addConnectorCustomizers(TomcatConnectorCustomizer...)` — mutate the **primary** connector (timeouts, max threads, `maxConnections`, `relaxedQueryChars`, etc.). - `addContextCustomizers(TomcatContextCustomizer...)` — tweak the Tomcat `Context`. Because these are Tomcat-specific, you target the concrete type in the generic parameter: ```java @Component class ExtraConnectorCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.addAdditionalTomcatConnectors(managementConnector()); } private Connector managementConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setScheme("http"); connector.setPort(8081); connector.setSecure(false); return connector; } } ``` ## Primary connector: use addConnectorCustomizers To change settings on the **existing** primary connector rather than add a new one, don't build a fresh `Connector`; use: ```java factory.addConnectorCustomizers(connector -> { connector.setProperty("maxConnections", "200"); ((Http11NioProtocol) connector.getProtocolHandler()) .setConnectionTimeout(30_000); }); ``` `TomcatConnectorCustomizer` is itself a functional interface (`void customize(Connector connector)`), invoked by the factory when it prepares the primary connector. ## Portability caveat Everything above binds you to Tomcat classes (`Connector`, `Http11NioProtocol`). If you swap the starter to Jetty (`JettyServletWebServerFactory`) or Undertow (`UndertowServletWebServerFactory`), this customizer's generic type no longer matches the active factory, so **it silently does not run**, and you'd need the equivalent Jetty/Undertow customizer (`addServerCustomizers`, `addBuilderCustomizers`). Keep container-specific customizers isolated and documented. ## Gotchas - Each additional connector needs a **distinct port**; a clash causes a bind failure at startup. - The extra connector doesn't inherit the primary's SSL/compression config — configure it explicitly. - Don't confuse `addAdditionalTomcatConnectors` (adds a listener) with `addConnectorCustomizers` (mutates the primary listener). - Exposing an unauthenticated management port has security implications — bind it to localhost or protect it (relevant to defense-in-depth).
- What's the difference between addAdditionalTomcatConnectors and addConnectorCustomizers?addAdditionalTomcatConnectors registers extra Connector listeners in addition to the primary one (each on its own port). addConnectorCustomizers takes TomcatConnectorCustomizer callbacks that mutate the primary connector Tomcat builds from server.* properties — you don't create a new Connector, you tweak the existing one.
- You wrote a WebServerFactoryCustomizer<TomcatServletWebServerFactory> but switched the starter to Undertow. What happens?It silently does nothing. The post-processor filters customizers by generic type; the active factory is UndertowServletWebServerFactory, which is not assignable to TomcatServletWebServerFactory, so the customizer is skipped. You'd need an Undertow-specific customizer.
saying these in an interview costs you the question
- Confusing addAdditionalTomcatConnectors with addConnectorCustomizers
- Thinking a second connector can be configured via server.* properties
- Expecting a Tomcat-typed customizer to run under Jetty/Undertow
- Forgetting the extra connector needs its own port and its own SSL config