Skip to content

18.4 Xây dựng và triển khai các tệp WAR

Trong suốt cuốn sách này, khi bạn phát triển các ứng dụng tạo nên ứng dụng Taco Cloud, bạn đã chạy chúng hoặc trong IDE hoặc từ dòng lệnh dưới dạng một tệp JAR thực thi. Trong cả hai trường hợp, một máy chủ Tomcat nhúng (hoặc Netty, trong trường hợp các ứng dụng Spring WebFlux) luôn có mặt để phục vụ các yêu cầu đến ứng dụng.

Nhờ phần lớn vào Spring Boot autoconfiguration, bạn đã không cần phải tạo tệp web.xml hoặc lớp khởi tạo servlet để khai báo DispatcherServlet của Spring cho Spring MVC. Nhưng nếu bạn định triển khai ứng dụng lên một máy chủ ứng dụng Java, bạn sẽ cần xây dựng một tệp WAR. Và, để máy chủ ứng dụng biết cách chạy ứng dụng, bạn cũng cần bao gồm một lớp khởi tạo servlet trong tệp WAR để thay thế cho tệp web.xml và khai báo DispatcherServlet.

Thật ra, việc đóng gói một ứng dụng Spring Boot thành tệp WAR không quá khó. Thậm chí, nếu bạn đã chọn tùy chọn WAR khi tạo ứng dụng qua Initializr, thì bạn không cần làm gì thêm nữa.

Initializr đảm bảo rằng dự án được tạo sẽ chứa một lớp khởi tạo servlet, và tệp build sẽ được cấu hình để tạo ra tệp WAR. Tuy nhiên, nếu bạn đã chọn tạo tệp JAR từ Initializr (hoặc nếu bạn tò mò muốn biết sự khác biệt liên quan), hãy đọc tiếp.

Trước tiên, bạn cần một cách để cấu hình DispatcherServlet của Spring. Mặc dù điều này có thể được thực hiện với một tệp web.xml, Spring Boot còn làm cho điều này dễ dàng hơn với SpringBootServletInitializer. SpringBootServletInitializer là một triển khai đặc biệt của WebApplicationInitializer có nhận thức về Spring Boot. Ngoài việc cấu hình DispatcherServlet của Spring, SpringBootServletInitializer cũng tìm các bean trong Spring application context có kiểu Filter, Servlet, hoặc ServletContextInitializer và liên kết chúng với servlet container.

Để sử dụng SpringBootServletInitializer, hãy tạo một lớp con và ghi đè phương thức configure() để chỉ định lớp cấu hình Spring. Đoạn mã sau đây trình bày TacoCloudServletInitializer, một lớp con của SpringBootServletInitializer mà bạn sẽ sử dụng cho ứng dụng Taco Cloud.

Listing 18.1 Enabling Spring web applications via Java

java
package tacos;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class IngredientServiceServletInitializer
        extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(
                    SpringApplicationBuilder builder) {
    return builder.sources(IngredientServiceApplication.class);
  }
}

Như bạn thấy, phương thức configure() nhận vào một SpringApplicationBuilder và trả về chính nó. Trong quá trình này, nó gọi phương thức sources() để đăng ký các lớp cấu hình Spring. Trong trường hợp này, nó chỉ đăng ký lớp TacoCloudApplication, lớp này đóng vai trò kép: vừa là lớp bootstrap (cho JAR thực thi) vừa là lớp cấu hình Spring.

Mặc dù ứng dụng có thể có các lớp cấu hình Spring khác, nhưng không cần thiết phải đăng ký tất cả chúng với phương thức sources(). Lớp TacoCloudApplication, với annotation @SpringBootApplication, đã ngầm cho phép cơ chế quét component (component scanning). Cơ chế quét component sẽ phát hiện và đưa vào các lớp cấu hình khác mà nó tìm thấy.

Phần lớn, lớp con của SpringBootServletInitializer là mã mẫu (boilerplate). Nó chỉ tham chiếu đến lớp cấu hình chính của ứng dụng. Ngoài điều đó ra, nó gần như giống nhau cho mọi ứng dụng mà bạn sẽ đóng gói thành WAR. Và bạn hầu như không bao giờ cần chỉnh sửa gì thêm.

Bây giờ khi bạn đã viết lớp khởi tạo servlet, bạn cần thực hiện một vài thay đổi nhỏ trong cấu hình build của dự án. Nếu bạn sử dụng Maven, thay đổi đơn giản là đảm bảo rằng phần tử <packaging> trong pom.xml được đặt là war, như sau:

html
<packaging>war</packaging>

Các thay đổi tương tự với Gradle cũng khá đơn giản. Bạn cần áp dụng plugin war trong tệp build.gradle như sau:

yaml
apply plugin: 'war'

Bây giờ bạn đã sẵn sàng để build ứng dụng. Với Maven, bạn sử dụng script Maven wrapper mà Initializr đã tạo để chạy lệnh package, như sau:

bash
mvnw package

Nếu build thành công, tệp WAR sẽ xuất hiện trong thư mục target. Ngược lại, nếu bạn sử dụng Gradle để build dự án, bạn dùng Gradle wrapper để chạy tác vụ build, như sau:

bash
gradlew build

Khi build hoàn tất, tệp WAR sẽ nằm trong thư mục build/libs. Việc còn lại là triển khai ứng dụng. Quy trình triển khai thay đổi tùy theo máy chủ ứng dụng, vì vậy hãy tham khảo tài liệu hướng dẫn triển khai cụ thể của máy chủ bạn đang sử dụng.

Có thể bạn sẽ thấy thú vị khi biết rằng mặc dù bạn đã tạo ra một tệp WAR phù hợp để triển khai lên bất kỳ container servlet nào hỗ trợ Servlet 3.0 (hoặc cao hơn), tệp WAR đó vẫn có thể được thực thi từ dòng lệnh như thể nó là một tệp JAR thực thi, như sau:

bash
java -jar target/taco-cloud-0.0.19-SNAPSHOT.war

Trên thực tế, bạn có hai tùy chọn triển khai chỉ từ một artifact duy nhất!

Released under the MIT License.