Giới thiệu và kiến trúc Spring Boot
Xem thửMột nhóm bốn người dựng dịch vụ đầu tiên của họ bằng Spring Framework thuần. Sau hai tuần họ có một ứng dụng chạy được, và một thư mục config với mười bốn lớp: cấu hình Tomcat, đăng ký DispatcherServlet, bộ chuyển đổi JSON, bộ xử lý lỗi, mã hóa ký tự, và những thứ khác mà mỗi người chép từ một dự án cũ. Dịch vụ thứ hai bắt đầu bằng việc chép nguyên thư mục đó, và mọi lỗi cấu hình của dịch vụ đầu tiên đi theo. Một người mới vào nhóm hỏi "tại sao chỗ này đặt thế?" và không ai trả lời được, vì cấu hình là kết quả của nhiều lần thử và sai.
Spring Boot sinh ra để giải đúng tình huống này: phần lớn cấu hình hạ tầng web, dữ liệu, bảo mật là giống nhau giữa các dự án, nên để framework chọn mặc định hợp lý theo những gì có trên classpath, và chỉ yêu cầu bạn viết phần khác biệt. Bài này kiểm kê điều đó bằng số liệu: bạn sẽ chạy một ứng dụng Boot nhỏ, in ra những gì Boot đã tự cấu hình, và đóng gói nó thành một tệp chạy được.
Sau bài này, bạn có thể
- Nêu Spring Boot thêm gì lên trên Spring Framework: starter, auto-configuration, server nhúng, đóng gói thực thi.
- Đọc báo cáo điều kiện của Boot để biết auto-configuration nào đã được áp dụng và vì sao.
- So sánh ứng dụng Boot với ứng dụng Spring MVC dựng bằng tay ở các bài trước.
- Đóng gói ứng dụng thành executable jar và hiểu cấu trúc của nó.
Chuẩn bị môi trường và dự án
Mọi thí nghiệm của bài chạy trong một dự án Maven nhỏ. Mục này nói rõ cần cài gì, khai báo thư viện nào và cấu hình ra sao; mã của từng lớp được trình bày ngay tại chỗ nó được dùng, kèm giải thích, nên bạn không cần mở nơi nào khác. Số liệu và thông báo lỗi trong bài được đo từ chính mã đó (JDK 17, Spring Boot 4.1.1, Spring Framework 7.0.9, Tomcat 11.0.24). Bản sao lưu cả dự án nằm ở kho mã của khóa học, thư mục 08-spring-boot/01-gioi-thieu-kien-truc, chỉ để bạn clone cho nhanh nếu không muốn tự gõ lại.
Yêu cầu môi trường
| Thành phần | Phiên bản đã kiểm chứng | Ghi chú |
|---|---|---|
| JDK | 17 trở lên | java -version |
| Maven | 3.9 trở lên | mvn -v |
| Spring Boot | 4.1.1 | khai báo ở parent trong pom.xml; quản lý Spring Framework 7.0.9 và Tomcat 11.0.24 |
| Docker | không cần | bài này không dùng cơ sở dữ liệu |
Cấu trúc
01-gioi-thieu-kien-truc/
pom.xml parent spring-boot-starter-parent 4.1.1, hai starter
src/main/java/dev/canhdominich/boot/tour/
Application.java @SpringBootApplication và main
HelloController.java @RestController với GET /hello
TourDemo.java khởi động ứng dụng và in bản kiểm kê
Khai báo thư viện: pom.xml
pom.xml
Dự án Maven dùng spring-boot-starter-parent 4.1.1 làm parent: parent quản lý phiên bản của mọi thư viện (Spring Framework 7.0.9, Tomcat 11.0.24, Jackson, và nhiều thứ khác) nên các dependency không ghi số phiên bản. spring-boot-starter-webmvc kéo Spring MVC, Tomcat nhúng và Jackson; spring-boot-starter-test phục vụ kiểm thử. spring-boot-maven-plugin đóng gói ứng dụng thành executable jar và cho phép mvn spring-boot:run.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>dev.canhdominich.javabackend</groupId>
<artifactId>boot-tour</artifactId>
<version>1.0.0</version>
<name>Spring Boot - Gioi thieu va kien truc</name>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Một ứng dụng Spring Boot nhỏ nhất
Một dự án Boot bắt đầu từ pom.xml. Điểm khác so với các lab trước: dự án khai báo spring-boot-starter-parent làm parent, và từ đó không cần ghi số phiên bản của từng thư viện; phiên bản do Boot quản lý một cách đồng bộ (Spring Framework 7.0.9, Tomcat 11.0.24 và các thư viện khác đều đi theo Boot 4.1.1). Phụ thuộc là hai starter: spring-boot-starter-webmvc (kéo Spring MVC, Tomcat nhúng, Jackson và những gì ứng dụng web cần) và spring-boot-starter-test (cho kiểm thử). Plugin spring-boot-maven-plugin đóng gói ứng dụng thành tệp chạy được ở mục sau.
Phần mã chỉ có hai lớp. Application có @SpringBootApplication và hàm main gọi SpringApplication.run:
src/main/java/dev/canhdominich/boot/tour/Application.java
package dev.canhdominich.boot.tour;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication là ba annotation gộp lại: @Configuration (lớp này có thể khai báo bean), @ComponentScan (quét package của lớp để tìm @Component, @RestController...) và @EnableAutoConfiguration (bật cơ chế tự cấu hình dựa trên classpath).
HelloController là một controller REST, giống những gì bạn viết ở bài MVC:
src/main/java/dev/canhdominich/boot/tour/HelloController.java
package dev.canhdominich.boot.tour;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public Map<String, String> hello() {
return Map.of("message", "Xin chao Spring Boot");
}
}
Trong cả hai lớp không có dòng nào tạo Tomcat, đăng ký DispatcherServlet hay chọn bộ chuyển đổi JSON. Phần dưới đo xem ai đã làm những việc đó.
Kiểm kê những gì Boot đã tự cấu hình
TourDemo khởi động chính Application với cổng ngẫu nhiên (server.port=0), rồi hỏi context: phiên bản, những bean do mã của bạn khai báo, những auto-configuration đã áp dụng hoặc không, các bean xử lý yêu cầu, rồi gửi hai yêu cầu HTTP thật. Nguồn thông tin chính là ConditionEvaluationReport, bản ghi mà Boot lưu về từng điều kiện đã đánh giá:
src/main/java/dev/canhdominich/boot/tour/TourDemo.java
package dev.canhdominich.boot.tour;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.SpringVersion;
import org.springframework.web.servlet.HandlerMapping;
public class TourDemo {
public static void main(String[] args) throws Exception {
run().forEach(System.out::println);
}
public static List<String> run() throws Exception {
List<String> lines = new ArrayList<>();
long start = System.nanoTime();
SpringApplication application = new SpringApplication(Application.class);
application.setDefaultProperties(java.util.Map.of("server.port", "0", "spring.main.banner-mode", "off", "logging.level.root", "WARN"));
try (ConfigurableApplicationContext context = application.run()) {
long millis = (System.nanoTime() - start) / 1_000_000;
lines.add("spring boot " + SpringBootVersion.getVersion() + ", spring framework " + SpringVersion.getVersion() + ", tomcat " + org.apache.catalina.util.ServerInfo.getServerNumber());
String[] beanNames = context.getBeanDefinitionNames();
Set<String> yours = Arrays.stream(beanNames)
.filter(name -> context.getBean(name).getClass().getName().startsWith("dev.canhdominich"))
.collect(Collectors.toCollection(TreeSet::new));
lines.add("beans in the context: " + (beanNames.length > 100 ? "more than 100" : beanNames.length) + ", declared by this project's classes: " + yours);
ConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());
List<String> matched = report.getConditionAndOutcomesBySource().entrySet().stream()
.filter(entry -> entry.getValue().isFullMatch())
.map(entry -> entry.getKey())
.filter(name -> name.endsWith("AutoConfiguration"))
.map(name -> name.substring(name.lastIndexOf('.') + 1))
.sorted()
.toList();
lines.add("auto-configurations that applied: " + matched.size() + " " + matched);
for (String name : List.of("DispatcherServletAutoConfiguration", "TomcatServletWebServerAutoConfiguration", "WebMvcAutoConfiguration", "JacksonAutoConfiguration", "HttpMessageConvertersAutoConfiguration", "ErrorMvcAutoConfiguration")) {
lines.add(" " + name + ": " + (matched.contains(name) ? "applied" : "not applied"));
}
List<String> skipped = report.getConditionAndOutcomesBySource().entrySet().stream()
.filter(entry -> !entry.getValue().isFullMatch())
.filter(entry -> entry.getKey().endsWith("AutoConfiguration"))
.map(entry -> entry.getKey().substring(entry.getKey().lastIndexOf('.') + 1))
.sorted()
.toList();
lines.add("auto-configurations whose conditions did not match: " + skipped.size() + " " + skipped);
lines.add("handler mappings: " + new TreeSet<>(context.getBeansOfType(HandlerMapping.class).keySet()));
int port = ((WebServerApplicationContext) context).getWebServer().getPort();
lines.add("embedded server listening on a port chosen by the OS: " + (port > 0));
lines.add(call(port, "/hello"));
lines.add(call(port, "/nope"));
lines.add("startup under 20 seconds: " + (millis < 20_000));
}
return lines;
}
private static String call(int port, String path) throws Exception {
HttpResponse<String> response = HttpClient.newHttpClient().send(
HttpRequest.newBuilder(URI.create("http://127.0.0.1:" + port + path)).GET().build(), HttpResponse.BodyHandlers.ofString());
String body = response.body().replaceAll("\"timestamp\":\"[^\"]*\",?", "");
return "GET " + path + " -> " + response.statusCode() + " " + response.headers().firstValue("Content-Type").orElse("") + " " + body;
}
}
Chạy bằng mvn -q compile exec:java -Dexec.mainClass=dev.canhdominich.boot.tour.TourDemo. Kết quả (đã bỏ log ở stderr):
spring boot 4.1.1, spring framework 7.0.9, tomcat 11.0.24.0
beans in the context: more than 100, declared by this project's classes: [application, helloController]
auto-configurations that applied: 11 [AopAutoConfiguration, DispatcherServletAutoConfiguration, ErrorMvcAutoConfiguration, HttpEncodingAutoConfiguration, HttpMessageConvertersAutoConfiguration, JacksonAutoConfiguration, MultipartAutoConfiguration, TaskExecutionAutoConfiguration, TaskSchedulingAutoConfiguration, TomcatServletWebServerAutoConfiguration, WebMvcAutoConfiguration]
DispatcherServletAutoConfiguration: applied
TomcatServletWebServerAutoConfiguration: applied
WebMvcAutoConfiguration: applied
JacksonAutoConfiguration: applied
HttpMessageConvertersAutoConfiguration: applied
ErrorMvcAutoConfiguration: applied
auto-configurations whose conditions did not match: 13 [JmxAutoConfiguration, MessageSourceAutoConfiguration, ServletHttpExchangesAutoConfiguration, ServletManagementContextAutoConfiguration, ServletMappingsAutoConfiguration, SpringApplicationAdminJmxAutoConfiguration, TomcatMetricsAutoConfiguration, TomcatReactiveManagementContextAutoConfiguration, TomcatReactiveWebServerAutoConfiguration, TomcatServletManagementContextAutoConfiguration, WebMvcHealthEndpointExtensionAutoConfiguration, WebMvcMappingsAutoConfiguration, WebMvcObservationAutoConfiguration]
handler mappings: [beanNameHandlerMapping, requestMappingHandlerMapping, resourceHandlerMapping, routerFunctionMapping, welcomePageHandlerMapping, welcomePageNotAcceptableHandlerMapping]
embedded server listening on a port chosen by the OS: true
GET /hello -> 200 application/json {"message":"Xin chao Spring Boot"}
GET /nope -> 404 application/json {"status":404,"error":"Not Found","path":"/nope"}
startup under 20 seconds: true
Đọc kết quả:
- Phiên bản đi cùng nhau. Boot 4.1.1 mang theo Spring Framework 7.0.9 và Tomcat 11.0.24: một bộ phiên bản đã được thử cùng nhau, không phải bạn tự ghép.
- Chỉ hai bean là của bạn. Trong cả context hơn một trăm bean, hai bean do lớp của dự án khai báo là
application(lớp@SpringBootApplicationcũng là một bean) vàhelloController. Phần còn lại đến từ Spring và từ auto-configuration. - Mười một auto-configuration đã áp dụng. Những cái đáng chú ý nhất chính là các thứ bạn tự viết ở bài MVC:
TomcatServletWebServerAutoConfigurationdựng và khởi động Tomcat,DispatcherServletAutoConfigurationđăng kýDispatcherServlet,WebMvcAutoConfigurationđăng ký các bean chiến lược của MVC,JacksonAutoConfigurationvàHttpMessageConvertersAutoConfigurationlo việc chuyển đối tượng thành JSON,ErrorMvcAutoConfigurationlo trang lỗi. - Mười ba cái không khớp điều kiện. Ví dụ
TomcatReactiveWebServerAutoConfigurationkhông áp dụng vì ứng dụng không dùng web reactive. Báo cáo điều kiện cho bạn biết lý do từng cái bị bỏ qua, đó là công cụ để trả lời "vì sao bean này có (hoặc không có)". - Các bean xử lý yêu cầu. Danh sách
handler mappingsgồm đủ những bean bạn thấy ở bài MVC (requestMappingHandlerMapping,beanNameHandlerMapping,routerFunctionMapping) cộng thêm vài cái của Boot (resourceHandlerMappingcho tệp tĩnh,welcomePageHandlerMapping). - Server nhúng đã chạy. Cổng do hệ điều hành chọn, và
GET /hellotrả JSON. Controller trả mộtMap, Jackson do Boot cấu hình chuyển nó thành JSON. - Lỗi có thân JSON.
GET /nopetrả 404 với thân{"status":404,"error":"Not Found","path":"/nope"}, nhờErrorMvcAutoConfiguration. Ở lab Spring MVC thuần, cùng loại yêu cầu chỉ có mã 404 và trang lỗi mặc định của Tomcat.
Cách đọc hình: cột trái là ba việc bạn tự làm ở lab Spring MVC (tạo Tomcat, đăng ký DispatcherServlet, bật cấu hình MVC); cột phải là auto-configuration của Boot làm cùng việc và đã được ghi nhận là "applied" trong báo cáo. Nét đứt nghĩa là cùng kết quả, khác người viết.
Cách đọc hình: hàng trên: 11 auto-configuration đã áp dụng vì các lớp của chúng có trên classpath. Hàng dưới: 13 cái bị bỏ qua vì một điều kiện không thỏa. Ô bên phải nhắc rằng chỉ hai bean trong hơn một trăm bean là do mã của bạn khai báo.
Đang tải Animation…
Cách Boot quyết định: starter, classpath và điều kiện
Chuỗi quyết định có ba mắt xích, và hiểu chúng giúp bạn làm chủ Boot thay vì xem nó là phép màu:
- Starter chọn thư viện. Một starter là một dependency "gói":
spring-boot-starter-webmvckéospring-webmvc, Tomcat nhúng và Jackson về classpath với phiên bản đã được Boot thử cùng nhau. Bạn không phải liệt kê từng thư viện. - Classpath là dữ liệu đầu vào. Mỗi auto-configuration có điều kiện: ví dụ chỉ áp dụng khi lớp
DispatcherServletcó trên classpath và ứng dụng là ứng dụng web servlet. Thay đổi dependency là thay đổi những auto-configuration được áp dụng. - Bạn luôn thắng. Hầu hết auto-configuration chỉ tạo bean khi bạn chưa tự khai báo một bean cùng loại (bài kế tiếp đo điều này), nên việc ghi đè là khai báo bean của riêng bạn, không phải sửa Boot.
Công cụ để kiểm tra là chính ConditionEvaluationReport (bạn vừa dùng) hoặc chạy ứng dụng với --debug để Boot in báo cáo điều kiện ra log.
Đóng gói thành executable jar
Bước cuối là phát hành. Với spring-boot-maven-plugin, mvn package tạo ra một tệp jar chạy được bằng java -jar mà không cần cài Tomcat. Kết quả đo trên máy tác giả:
target/boot-tour-1.0.0.jar: 19,9 MB
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: dev.canhdominich.boot.tour.Application
Spring-Boot-Version: 4.1.1
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
số jar trong BOOT-INF/lib: 34
BOOT-INF/lib/spring-boot-4.1.1.jar, spring-boot-autoconfigure-4.1.1.jar, spring-boot-tomcat-4.1.1.jar, tomcat-embed-core-11.0.24.jar, jackson-databind-3.1.5.jar, ...
Started Application in 3.165 seconds
Cấu trúc này đáng hiểu: manifest của jar trỏ Main-Class tới JarLauncher (một lớp của Boot), không phải tới Application. JarLauncher biết cách đọc các jar lồng bên trong BOOT-INF/lib và dựng classpath từ đó, rồi gọi Start-Class là hàm main của bạn. Mã đã biên dịch của bạn nằm ở BOOT-INF/classes. Một tệp duy nhất mang theo toàn bộ thư viện: đó là lý do chạy curl http://localhost:18091/hello (cổng đặt bằng --server.port=18091) trả {"message":"Xin chao Spring Boot"} ngay sau java -jar.
Cách đọc hình: java -jar chạy JarLauncher (Main-Class), nó dựng classpath từ BOOT-INF/classes và 34 jar trong BOOT-INF/lib, rồi gọi Application.main (Start-Class).
Bài tiếp theo (đọc cấu hình) vẫn dùng đúng cơ chế này để cho bạn đổi hành vi của ứng dụng mà không đổi mã.
Cách đọc hình: hàng trên: ở lab Spring MVC thuần, 404 do Tomcat trả lời theo kiểu của nó. Hàng dưới: Boot có ErrorMvcAutoConfiguration, trả 404 kèm thân JSON mà ứng dụng client đọc được.
Quyết định thiết kế và đánh đổi
| Quyết định | Lựa chọn | Đánh đổi |
|---|---|---|
| Quản lý phiên bản | spring-boot-starter-parent | Nâng Boot kéo theo nhiều thư viện nâng cùng lúc |
| Cấu hình web | Auto-configuration | Phải biết cách đọc báo cáo điều kiện khi hành vi khó hiểu |
| Chạy ứng dụng | Server nhúng, một tệp jar | Mỗi ứng dụng mang theo server của nó |
| Ghi đè mặc định | Tự khai báo bean cùng loại | Cần biết bean nào do auto-configuration tạo |
| Phụ thuộc | Starter thay vì từng thư viện | Kéo nhiều jar hơn mức bạn dùng thật (34 jar ở bài này) |
Playbook: gặp sự cố khởi động Boot thì làm gì
| Triệu chứng | Kiểm tra đầu tiên | Nguyên nhân hay gặp | Cách xử lý |
|---|---|---|---|
| Không biết bean này do đâu | Báo cáo điều kiện (--debug) | Auto-configuration tạo bean | Đọc báo cáo, ghi đè bằng bean của bạn |
| Thiếu một tính năng mong đợi | Starter có trong pom.xml không | Thiếu dependency nên điều kiện không khớp | Thêm starter tương ứng |
Port 8080 was already in use | Tiến trình đang dùng cổng | Ứng dụng khác chiếm cổng | --server.port=... |
| Jar chạy báo thiếu lớp | Plugin đóng gói | Dùng mvn package mà không có spring-boot-maven-plugin | Giữ plugin trong pom.xml |
| Controller không được quét | Package của controller | Nằm ngoài package của @SpringBootApplication | Đưa controller vào cùng package hoặc package con |
Lỗi thường gặp khi chạy lab
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
mvn không tải được thư viện Spring Boot | Chưa có mạng | Chạy lại với mạng |
Port 8080 was already in use | Cổng 8080 đang bị chiếm | java -jar target/boot-tour-1.0.0.jar --server.port=8081 |
Bài thực hành
Làm trong dự án của bài (thư mục 08-spring-boot/01-gioi-thieu-kien-truc). Sau mỗi bước, so kết quả với tiêu chí nghiệm thu.
- Chạy bản kiểm kê.
mvn -q compile exec:java -Dexec.mainClass=dev.canhdominich.boot.tour.TourDemo. Tiêu chí: số auto-configuration áp dụng là 11 và không khớp là 13, và hai yêu cầu HTTP khớp bài. - Chạy như server thật.
mvn -q spring-boot:runrồicurl http://localhost:8080/hello. Tiêu chí:{"message":"Xin chao Spring Boot"}; thửcurl -i http://localhost:8080/nopevà ghi lại mã cùng thân. - Đóng gói.
mvn -q package -DskipTests, rồiunzip -p target/boot-tour-1.0.0.jar META-INF/MANIFEST.MF. Tiêu chí:Main-Classlàorg.springframework.boot.loader.launch.JarLaunchervàStart-Classlàdev.canhdominich.boot.tour.Application. - Xem báo cáo điều kiện của Boot. Chạy
java -jar target/boot-tour-1.0.0.jar --debugvà tìm phầnCONDITIONS EVALUATION REPORT. Tiêu chí: tìm thấyDispatcherServletAutoConfigurationtrong nhómPositive matchesvà ghi lại một cái trong nhómNegative matchescùng lý do. - Đặt cổng. Chạy
java -jar target/boot-tour-1.0.0.jar --server.port=8088và gọi/helloở cổng đó. Tiêu chí: trả 200. - Chạy bộ test (tùy chọn). Bộ test nằm trong bản sao lưu ở kho mã của khóa học; sau khi clone,
mvn testchoTests run: 4, Failures: 0, Errors: 0. Dọn dẹp bằngmvn clean.
Hiểu lầm và giới hạn
- "Spring Boot là một framework khác." Nó dùng chính Spring Framework; nó thêm cấu hình tự động, starter và đóng gói.
- "Auto-configuration là phép màu." Mỗi cái là một lớp cấu hình có điều kiện, kiểm tra được bằng báo cáo.
- "Boot chạy trong Tomcat bạn cài." Server nằm trong jar của ứng dụng.
- Số đo thuộc về Spring Boot 4.1.1 (Spring Framework 7.0.9, Tomcat 11.0.24, JDK 17); số auto-configuration thay đổi theo dependency và phiên bản. Bài chưa nói về
application.properties(bài sau), profile, actuator, và cách đóng gói thành Docker image.
Tự kiểm tra
- Nêu ba điều Spring Boot thêm lên trên Spring Framework.
@SpringBootApplicationgồm những annotation nào?- Làm sao biết một bean do auto-configuration nào tạo ra, và vì sao một auto-configuration không được áp dụng?
Main-Classtrong manifest của executable jar là lớp nào, và vì sao không phảiApplication?- Starter khác một dependency thường ở điểm nào?
Gợi ý đáp án. (1) Starter, auto-configuration theo classpath, server nhúng cùng đóng gói thực thi (và quản lý phiên bản). (2) @Configuration, @ComponentScan, @EnableAutoConfiguration. (3) Dùng báo cáo điều kiện (ConditionEvaluationReport hoặc --debug): nó ghi cả điều kiện khớp và không khớp. (4) JarLauncher, vì nó dựng classpath từ các jar lồng trong BOOT-INF/lib trước rồi mới gọi Start-Class. (5) Nó là gói nhiều dependency cùng phiên bản tương thích cho một mục đích.
Điều cần nhớ
- Boot = Spring Framework + starter + auto-configuration + server nhúng + đóng gói thực thi.
- Classpath là đầu vào của auto-configuration; thay dependency là thay hành vi.
- Bạn ghi đè mặc định bằng cách tự khai báo bean; báo cáo điều kiện cho biết ai tạo gì.
java -jarchạyJarLauncher, nó nạp jar lồng nhau rồi gọimaincủa bạn.
Đọc thêm
- Spring Boot Reference: Getting Started
- Spring Boot Reference: Auto-configuration
- Spring Boot Reference: Executable Jars
Bài tiếp theo xem application.properties, profile và @ConfigurationProperties: các nút bạn vặn để đổi hành vi mà không sửa mã.