Master Multi‑Module Spring Boot 3: Build Independent Sub‑Modules with a Shared Parent
This article demonstrates a Spring Boot 3 multi‑module architecture where each module runs its own DispatcherServlet and ApplicationContext while sharing a common parent container, providing complete code examples, configuration steps, and testing insights for building loosely‑coupled backend services.
Environment: SpringBoot 3.4.2
1. Introduction
In a previous article we introduced a multi‑module development approach that starts multiple Tomcat instances in a single Spring Boot project. This article presents another approach where each module has an independent DispatcherServlet and its own ApplicationContext, while sharing a common parent container.
2. Practical Cases
2.1 User Module
Entity defined as a Java record:
public record User(Long id, String name, Integer age) {}Simple controller:
@RestController
public class UserController {
@GetMapping("/u/query")
public ResponseEntity<User> query() {
return ResponseEntity.ok(new User(1L, "pack", 22));
}
}Configuration scans the user package and enables Spring MVC:
@Configuration
@ComponentScan(basePackages = {"cn.pack.module.user"})
@EnableWebMvc
public class UserConfig {}2.2 Order Module
Entity: public record Order(Long id, String orderNo) {} Controller injects a common service from the parent container:
@RestController
public class OrderController {
private final CommonService commonService;
public OrderController(CommonService commonService) {
this.commonService = commonService;
}
@GetMapping("/o/query")
public ResponseEntity<Order> query() {
this.commonService.query();
return ResponseEntity.ok(new Order(66L, "XP00001"));
}
}Configuration:
@Configuration
@ComponentScan(basePackages = {"cn.pack.module.order"})
@EnableWebMvc
public class OrderConfig {}2.3 Parent Container
Common service shared by sub‑modules:
@Service
public class CommonService {
public void query() {
System.err.println("Common service query...");
}
}Initializer for the user module creates a child AnnotationConfigServletWebApplicationContext, registers UserConfig, and maps the servlet to /users/*:
@Component
public class UserServletContextInitializer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();
context.setServletContext(servletContext);
context.register(UserConfig.class);
DispatcherServlet servlet = new DispatcherServlet();
servlet.setApplicationContext(context);
Dynamic dynamic = servletContext.addServlet("userDispatcherServlet", servlet);
dynamic.addMapping("/users/*");
dynamic.setAsyncSupported(true);
}
}Order module initializer is analogous, mapping to /orders/*:
@Component
public class OrderServletContextInitializer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();
context.setServletContext(servletContext);
context.register(OrderConfig.class);
DispatcherServlet servlet = new DispatcherServlet();
servlet.setApplicationContext(context);
Dynamic dynamic = servletContext.addServlet("orderDispatcherServlet", servlet);
dynamic.addMapping("/orders/*");
dynamic.setAsyncSupported(true);
}
}2.4 Testing
When accessing /orders/query the console prints “Common service query…”. Accessing /users/query returns 404 because the servlet is mapped to /users/* only.
2.5 Why does the order module see the parent bean?
During DispatcherServlet initialization, FrameworkServlet.initServletBean() sets the parent WebApplicationContext and refreshes the context, allowing child modules to inherit beans from the shared parent.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
