NeuroAgent

Why Spring Boot requires different ports for context hierarchy

Explanation of differences between SpringApplicationBuilder and ServletRegistrationBean in Spring Boot. Learn why context hierarchy requires different ports while ServletRegistrationBean works on a single port.

Question

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?

NeuroAgent

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

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:

java
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:

java
@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:

  1. Independent contexts = independent servers: Each child context in a SpringApplicationBuilder hierarchy is created as a separate web application with its own server instance
  2. No shared ServletContext: Contexts do not share a ServletContext, which is necessary for multiple servlets to operate on one port
  3. 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:

  1. Single context: All servlets are registered within the same WebApplicationContext
  2. Shared ServletContext: Servlets share one ServletContext, which manages the servlet lifecycle
  3. 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:

java
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

java
@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:

java
@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:

  1. SpringApplicationBuilder creates fully isolated web applications, each with its own server and port
  2. 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

  1. Spring Boot And Context Handling - ccbill.com
  2. Context Hierarchy :: Spring Framework - docs.spring.io
  3. Spring Web Contexts | Baeldung
  4. SpringApplicationBuilder tutorial - zetcode.com
  5. Context Hierarchy with the Spring Boot Fluent Builder API | Baeldung
  6. Servlet Web Applications :: Spring Boot - docs.spring.io
  7. Spring Boot Features - docs.spring.io
  8. How to configure port for a Spring Boot application - Stack Overflow