Việc tích hợp máy chủ web Tomcat vào ứng dụng Spring Boot không yêu cầu cấu hình thủ công hay triển khai bên ngoài — toàn bộ quá trình được điều khiển tự động thông qua cơ chế cấu hình có điều kiện, khởi tạo thành phần và quản lý vòng đời. Dưới đây là phân tích kỹ thuật về cách Spring Boot xây dựng, cấu hình và kích hoạt Tomcat nhúng trong thời gian chạy.
1. Cơ chế chọn máy chủ dựa trên phụ thuộc lớp
Khi thêm spring-boot-starter-web vào dự án Maven/Gradle, hệ thống tự động kéo theo spring-boot-starter-tomcat, bao gồm các thư viện như tomcat-embed-core, tomcat-embed-el, và tomcat-embed-websocket. Trong giai đoạn khởi động, Spring Boot đọc tệp META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (hoặc spring.factories ở phiên bản cũ hơn) để đăng ký lớp ServletWebServerFactoryAutoConfiguration. Lớp này chỉ được kích hoạt nếu:
- Ứng dụng đang chạy trong môi trường servlet (
@ConditionalOnWebApplication(type = Type.SERVLET)), - Và lớp
ServletRequesttồn tại trong classpath (@ConditionalOnClass(ServletRequest.class)).
Ngoài ra, Spring Boot sử dụng @Import({TomcatServletWebServerFactoryConfiguration.class, ...}) để nạp các cấu hình cụ thể cho từng máy chủ. Việc lựa chọn giữa Tomcat, Jetty hay Undertow được thực hiện động: nếu Tomcat.class có mặt trong classpath thì TomcatServletWebServerFactory được ưu tiên; ngược lại, hệ thống sẽ thử nghiệm các factory tương ứng khác.
2. Khởi tạo và thiết lập đối tượng Tomcat
Quá trình bắt đầu từ ServletWebServerApplicationContext, nơi phương thức onRefresh() được ghi đè để gọi createWebServer(). Hàm này lấy một factory (thường là TomcatServletWebServerFactory) rồi gọi getWebServer(...) để tạo máy chủ:
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat server = new Tomcat();
File tempDir = determineTempDir();
server.setBaseDir(tempDir.getAbsolutePath());
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(getPort());
connector.setUriEncoding(getUriEncoding());
connector.setProperty("connectionTimeout", String.valueOf(getConnectionTimeout().toMillis()));
server.getService().addConnector(connector);
server.setConnector(connector);
prepareEmbeddedContext(server.getHost(), initializers);
return new TomcatWebServer(server, getAutoStart());
}
Trong đó:
determineTempDir()xác định thư mục tạm dùng làmbaseDircho Tomcat,prepareEmbeddedContext()tạoTomcatEmbeddedContext, thiết lậpcontextPath,docBase, và gắn cácServletContextInitializer— đặc biệt làDispatcherServletRegistrationBean, đảm bảo Spring MVC được đăng ký đúng cách vào container.
3. Quy trình khởi động và đồng bộ hóa với ApplicationContext
Sau khi TomcatWebServer được trả về, hàm khởi tạo của nó gọi initialize() — dẫn đến lệnh server.start(). Lúc này, Tomcat tiến hành:
- Khởi tạo các thành phần lõi:
Service,Engine,Host,Context, - Khởi động các connector và thread pool,
- Gọi
ServletContextInitializer.onStartup()để đăng ký các filter, listener và servlet.
Đồng thời, ServletWebServerApplicationContext chờ đến khi Tomcat báo cáo trạng thái STARTED, sau đó tiếp tục hoàn tất chu kỳ refresh(): tải bean, xử lý @PostConstruct, khởi chạy CommandLineRunner, v.v.
4. Các điểm mở rộng chính trong mã nguồn
| Thành phần | Vị trí | Mục đích |
|---|---|---|
ServletWebServerFactoryAutoConfiguration |
spring-boot-autoconfigure |
Kích hoạt factory phù hợp dựa trên điều kiện classpath |
TomcatServletWebServerFactory |
spring-boot-web |
Tạo và tùy chỉnh đối tượng Tomcat trước khi khởi động |
TomcatWebServer |
spring-boot-web |
Bao bọc lifecycle của Tomcat, hỗ trợ dừng mềm (stop()), kiểm tra trạng thái |
ServletWebServerApplicationContext |
spring-boot-web |
Thay thế AnnotationConfigServletWebServerApplicationContext để tích hợp máy chủ web |
5. Tùy biến nâng cao
-
Thay đổi máy chủ mặc định: Loại bỏ
spring-boot-starter-tomcat, thêmspring-boot-starter-jetty, và Spring Boot sẽ tự động sử dụngJettyServletWebServerFactory. -
Cấu hình qua file:
server:
port: 8082
shutdown: graceful
server.tomcat:
max-connections: 8192
accept-count: 100
background-processor-delay: 10
- Tùy chỉnh lập trình:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> secureTomcatCustomizer() {
return factory -> {
factory.addAdditionalTomcatConnectors(createHttpToHttpsRedirectConnector());
};
}
private Connector createHttpToHttpsRedirectConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}