Why does each context require a separate port when creating a Spring Boot context hierarchy using the Fluent API, while both DispatcherServlets work on the same port when using ServletRegistrationBean?
Spring Boot Creates Different Ports for Contexts in Fluent API Hierarchy
Spring Boot creates different ports for contexts in a Fluent API hierarchy because each child context starts its own instance of an embedded servlet container, while ServletRegistrationBean registers multiple servlets within the same context that uses a single servlet container instance.
- SpringApplicationBuilder Context Hierarchy
- ServletRegistrationBean Approach
- Technical Comparison of Approaches
- Practical Configuration Examples
- Recommendations for Choosing an Approach
SpringApplicationBuilder Context Hierarchy
SpringApplicationBuilder provides a fluent API for creating context hierarchies using the parent(), child(), and sibling() methods. The key feature of this approach is that each child context creates its own independent web server instance.
When you create a context hierarchy using SpringApplicationBuilder:
SpringApplicationBuilder appBuilder = new SpringApplicationBuilder()
.parent(RootContext.class)
.child(ChildContext1.class)
.sibling(ChildContext2.class);
ConfigurableApplicationContext applicationContext = appBuilder.run();
Each child context (ChildContext1 and ChildContext2):
- Starts its own embedded servlet container (Tomcat, Jetty, etc.)
- Requires separate port configuration via
server.port - Operates as a separate web application
As noted in the Spring documentation, when using SpringApplicationBuilder to create a context hierarchy, each context “expects to listen on different ports,” which requires explicit port configuration for each child context.
The SpringApplicationBuilder approach creates different virtual applications, each with its own port. This is useful for complete context isolation but increases resource consumption.
ServletRegistrationBean Approach
ServletRegistrationBean provides an alternative way to configure multiple DispatcherServlets within a single application context. In this approach, all servlets operate within the same web server.
Example configuration for multiple DispatcherServlets:
@Configuration
public class ServletConfig {
@Bean(name = "apiDispatcherServlet")
public DispatcherServlet apiDispatcherServlet(WebApplicationContext webApplicationContext) {
return new DispatcherServlet(webApplicationContext);
}
@Bean
public ServletRegistrationBean<DispatcherServlet> apiDispatcherServletRegistration() {
ServletRegistrationBean<DispatcherServlet> registration =
new ServletRegistrationBean<>(apiDispatcherServlet(), "/api/*");
registration.setName("apiDispatcherServlet");
return registration;
}
@Bean(name = "webDispatcherServlet")
public DispatcherServlet webDispatcherServlet(WebApplicationContext webApplicationContext) {
return new DispatcherServlet(webApplicationContext);
}
@Bean
public ServletRegistrationBean<DispatcherServlet> webDispatcherServletRegistration() {
ServletRegistrationBean<DispatcherServlet> registration =
new ServletRegistrationBean<>(webDispatcherServlet(), "/web/*");
registration.setName("webDispatcherServlet");
return registration;
}
}
When using ServletRegistrationBean:
- All servlets operate on one port (usually 8080)
- Differentiation is achieved through URL mapping (
/api/*,/web/*) - Servlets share the same ServletContext and resources
As explained in the official Spring Boot documentation: “If there is only one servlet in the context, it will be mapped to /. In the case of multiple servlet beans, the bean name will be used as a path prefix.” This allows multiple servlets to coexist on a single port.
Technical Comparison of Approaches
Architectural Differences
| Characteristic | SpringApplicationBuilder Hierarchy | ServletRegistrationBean |
|---|---|---|
| Number of Servers | Multiple independent servers | One server |
| Ports | Different ports for each context | One shared port |
| Resources | High consumption | Optimal usage |
| Isolation | Complete context isolation | Partial isolation |
| Configuration | Separate properties for each context | Shared properties |
Why Different Ports in SpringApplicationBuilder?
The reason SpringApplicationBuilder requires different ports lies in the architectural differences:
- Independent contexts = independent servers: Each child context in a SpringApplicationBuilder hierarchy is created as a separate web application with its own server instance
- No shared ServletContext: Contexts do not share a ServletContext, which is necessary for multiple servlets to operate on one port
- Port conflicts: Attempting to run multiple contexts on the same port would cause port binding conflicts
As noted in the Spring documentation: “DispatcherServlet expects a WebApplicationContext for its configuration. WebApplicationContext has a relationship with the ServletContext and the servlet it is associated with.”
Why ServletRegistrationBean Works on One Port?
ServletRegistrationBean successfully works on one port because:
- Single context: All servlets are registered within the same WebApplicationContext
- Shared ServletContext: Servlets share one ServletContext, which manages the servlet lifecycle
- URL routing: Different URL patterns (
/api/*,/web/*) allow requests to be directed to the appropriate servlets
Practical Configuration Examples
Port Configuration for SpringApplicationBuilder
To configure different ports in a SpringApplicationBuilder hierarchy:
public class MultiPortApplication {
public static void main(String[] args) {
// Parent context without web components
ApplicationContext parentContext = new SpringApplicationBuilder(ParentConfig.class)
.web(WebApplicationType.NONE)
.run();
// Child context 1 on port 8080
ApplicationContext child1Context = new SpringApplicationBuilder(Child1Config.class)
.parent(parentContext)
.properties("server.port=8080")
.run();
// Child context 2 on port 8081
ApplicationContext child2Context = new SpringApplicationBuilder(Child2Config.class)
.parent(parentContext)
.properties("server.port=8081")
.run();
}
}
ServletRegistrationBean Configuration with One Port
@Configuration
public class MultiServletConfig {
@Bean
public ServletRegistrationBean<DispatcherServlet> apiServletRegistration() {
DispatcherServlet apiServlet = new DispatcherServlet();
ServletRegistrationBean<DispatcherServlet> registration =
new ServletRegistrationBean<>(apiServlet, "/api/*");
registration.setName("apiServlet");
registration.setLoadOnStartup(1);
return registration;
}
@Bean
public ServletRegistrationBean<DispatcherServlet> webServletRegistration() {
DispatcherServlet webServlet = new DispatcherServlet();
ServletRegistrationBean<DispatcherServlet> registration =
new ServletRegistrationBean<>(webServlet, "/web/*");
registration.setName("webServlet");
registration.setLoadOnStartup(1);
return registration;
}
}
Recommendations for Choosing an Approach
When to Use SpringApplicationBuilder Hierarchy:
- Complete context isolation: When you need to isolate business logic, configuration, or dependencies
- Different technology stacks: When different contexts use different library versions or different frameworks
- Microservice architecture: When each context represents a logical microservice
- Testing: When you need to test contexts independently
When to Use ServletRegistrationBean:
- Resource optimization: When minimizing memory and CPU consumption is important
- Single authentication: When all servlets should use a shared authentication system
- Shared services: When servlets should share common services and components
- REST+UI application: When you need to separate REST API and web interface within one application
Hybrid Approach
In some cases, you can combine both approaches:
@SpringBootConfiguration
public class HybridConfig {
// Root context with shared services
@Bean
public SpringApplicationBuilder rootContext() {
return new SpringApplicationBuilder(RootConfig.class)
.web(WebApplicationType.NONE);
}
// Child context with ServletRegistrationBean
@Bean
public SpringApplicationBuilder childContext(SpringApplicationBuilder root) {
return root.child(WebConfig.class)
.properties("server.port=8080");
}
}
Conclusion
The key difference between SpringApplicationBuilder and ServletRegistrationBean lies in the architectural approach to context management:
- SpringApplicationBuilder creates fully isolated web applications, each with its own server and port
- ServletRegistrationBean registers multiple servlets within a single web application operating on a single port
The choice of approach depends on isolation requirements, resource constraints, and application architecture. For most standard web applications, ServletRegistrationBean provides a more efficient solution, while SpringApplicationBuilder hierarchy is suitable for complex scenarios requiring complete context isolation.
Sources
- Spring Boot And Context Handling - ccbill.com
- Context Hierarchy :: Spring Framework - docs.spring.io
- Spring Web Contexts | Baeldung
- SpringApplicationBuilder tutorial - zetcode.com
- Context Hierarchy with the Spring Boot Fluent Builder API | Baeldung
- Servlet Web Applications :: Spring Boot - docs.spring.io
- Spring Boot Features - docs.spring.io
- How to configure port for a Spring Boot application - Stack Overflow