Spring Framework và Spring Boot không cạnh tranh với nhau, và Boot cũng không phải một phiên bản Spring mới hơn. Boot là một lớp default nằm trên Framework, quyết định xem một application thông thường nhiều khả năng cần gì, rồi config sẵn phần đó cho bạn. Bỏ lớp này đi thì mọi khái niệm Spring bên dưới vẫn y nguyên — chỉ là bạn phải tự viết toàn bộ phần config.
Nhờ vậy câu hỏi "hai cái khác nhau chỗ nào" có một câu trả lời cụ thể và đo được: đó chính là tập hợp những việc Boot làm hộ. Bài này đo từng việc một. Mọi version, dependency tree và dòng log bên dưới đều lấy ra từ một build thật.
![]()
Toàn bộ bài chạy trên OpenJDK 21.0.6 với Spring Boot 4.1.1 và Gradle 9.7.1, dùng một project sinh từ Spring Initializr và build bằng Gradle wrapper đi kèm.
Spring Framework là container, Spring Boot là những lựa chọn mặc định
Spring Framework là phần runtime: nó khởi tạo object của bạn, inject các collaborator vào, proxy chúng để làm transaction và security, và cung cấp web stack. Nó cũ, ổn định và cố tình không áp đặt gì cả — bạn config sao thì nó chạy vậy, và trước đây bạn phải config tất cả.
Spring Boot thêm đúng bốn thứ lên trên, không có khái niệm nào mới về mặt lý thuyết:
| Boot đóng góp | Nó bỏ đi việc gì |
|---|---|
| Starter | đi tìm đủ mười lăm artifact cho một tính năng |
| Dependency management (một BOM) | tự chọn version sao cho khớp nhau |
| Auto-configuration | viết các class @Configuration mà app nào cũng phải viết |
| Embedded server và launcher | cài servlet container rồi deploy WAR vào đó |
Mỗi bản Boot gắn chặt với một bản Framework, và bạn không chọn riêng từng cái. Boot 4.1.1 chính là Framework 7.0.9, và BOM spring-boot-dependencies nói thẳng điều đó:
<spring-framework.version>7.0.9</spring-framework.version>Dependency tree sau khi resolve cũng khớp. Mọi artifact org.springframework trên classpath của một project Boot 4.1.1 đều về 7.0.9 mà không ai phải yêu cầu:
\--- org.springframework.boot:spring-boot-starter-webmvc -> 4.1.1
+--- org.springframework.boot:spring-boot-starter:4.1.1
| +--- org.springframework.boot:spring-boot-autoconfigure:4.1.1
| | \--- org.springframework.boot:spring-boot:4.1.1
| | +--- org.springframework:spring-core:7.0.9
| | \--- org.springframework:spring-context:7.0.9Nhánh 4.x có hai hệ quả thực tế. Boot 4 được compile cho Java 17 — class file trong spring-boot-4.1.1.jar mang major version 61 — nên 17 là mức sàn, còn thực tế bạn sẽ chọn 21 hoặc 25. Và Boot 3.5 đã hết open-source support từ 2026-06-30, đó là lý do một project mới bắt đầu hôm nay nên khởi động thẳng từ 4.x.
Một web application Spring Framework thuần bắt bạn viết những gì
Trước khi có Boot, "một web application Spring" nghĩa là tự lắp ráp từng mảnh. Đoạn dưới mang tính minh hoạ chứ không phải thứ đáng chạy lại hôm nay, nhưng từng mục trong đó đều là việc thật.
Đầu tiên là một class bootstrap để báo cho servlet container biết Spring tồn tại và nó quản những URL nào — hoặc bản web.xml tương đương:
public class WebInit implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext ctx) {
var ac = new AnnotationConfigWebApplicationContext();
ac.register(WebConfig.class);
var reg = ctx.addServlet("dispatcher", new DispatcherServlet(ac));
reg.setLoadOnStartup(1);
reg.addMapping("/");
}
}Tiếp theo là một class config để bật hạ tầng MVC và khai báo response được serialize ra sao:
@Configuration
@EnableWebMvc
@ComponentScan("com.example.demo")
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}Rồi đến một build file liệt kê từng artifact kèm version riêng, một bước đóng gói WAR, và một Tomcat đã cài sẵn trên máy sẽ chạy cái WAR đó.
Phần đo được ở đây là dependency graph. Chỉ khai spring-webmvc — với version gõ tay, vì chẳng có gì quản lý nó — sẽ resolve ra mười một jar và 8.3 MiB:
\--- org.springframework:spring-webmvc:7.0.9
+--- org.springframework:spring-aop:7.0.9
+--- org.springframework:spring-beans:7.0.9
+--- org.springframework:spring-context:7.0.9
| \--- io.micrometer:micrometer-observation:1.16.7
+--- org.springframework:spring-expression:7.0.9
\--- org.springframework:spring-web:7.0.9Đó là mốc trung thực: chỉ có MVC stack, không gì khác. Không servlet container, không thư viện JSON, không logging backend, không cơ chế bind config, và không có cách nào khởi động nó lên. Tất cả những thứ đó là các quyết định riêng, với những version riêng.
Spring Boot thay thế bằng cái gì
Cũng application đó, trên Boot, chỉ là một class:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}Mười ba dòng, trong đó bốn dòng là package và import. Không có initializer, không @EnableWebMvc, không phải đăng ký DispatcherServlet, không danh sách message converter, và không phải cài servlet container nào. Build file đi kèm dài hai mươi ba dòng không trống, và khối dependency chiếm bốn dòng:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
Đọc từng dòng một sẽ thấy: không có gì ở phía Boot là khái niệm Spring mới. DispatcherServletAutoConfiguration đăng ký đúng cái DispatcherServlet mà WebInit ở trên đã đăng ký. Khác biệt nằm ở chỗ ai là người viết đoạn đăng ký đó.
⚠️ Trên Boot 4, web starter là
spring-boot-starter-webmvcchứ không phảispring-boot-starter-web. Tên cũ vẫn resolve được — thậm chí ra đúng classpath 39 jar y hệt — nhưng POM của nó trên Maven Central giờ tự mô tả là "Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container (deprecated in favor of spring-boot-starter-webmvc)". Về phía test, Initializr giờ sinh raspring-boot-starter-webmvc-testhẹp hơn thay chospring-boot-starter-testtổng quát, cái vẫn tồn tại và không hề bị deprecated. Gần như mọi tutorial bạn tìm được vẫn ghi-web, vì đó là tên dùng suốt cả thập kỷ.
Một Spring Boot starter thực chất là gì?
Starter là một POM không chứa code. Nó compile ra không class nào, không mang annotation nào và không tự thêm hành vi gì. Việc duy nhất nó làm là gọi tên một nhóm artifact đã được chọn lọc, để bạn thêm một coordinate vào build là có cả nhóm đó.
spring-boot-starter-webmvc khai báo năm dependency trực tiếp. Resolve hết transitive ra được 39 jar và 18.8 MiB trên runtime classpath:

Đây là report thật, cắt ở tầng đầu tiên:
\--- org.springframework.boot:spring-boot-starter-webmvc -> 4.1.1
+--- org.springframework.boot:spring-boot-starter:4.1.1
+--- org.springframework.boot:spring-boot-starter-jackson:4.1.1
+--- org.springframework.boot:spring-boot-starter-tomcat:4.1.1
+--- org.springframework.boot:spring-boot-http-converter:4.1.1
\--- org.springframework.boot:spring-boot-webmvc:4.1.1Ba trong năm cái đó bản thân cũng là starter. spring-boot-starter là nền mà mọi starter khác đều phụ thuộc vào — core container cộng logging cộng phần đọc YAML. spring-boot-starter-tomcat là embedded servlet container. spring-boot-starter-jackson là JSON. Chính cách ghép này giải thích vì sao một dòng lại cho bạn một HTTP server chạy được và nói được JSON.
Boot 4.1.1 publish 170 starter. Đây là những cái bạn gặp đầu tiên, kèm mô tả lấy từ chính POM của chúng:
| Starter | Dùng để làm gì |
|---|---|
spring-boot-starter | starter nền: auto-configuration, logging và YAML |
spring-boot-starter-webmvc | Spring MVC và Tomcat |
spring-boot-starter-webflux | WebFlux và Reactor Netty, cho stack reactive |
spring-boot-starter-data-jpa | Spring Data JPA với Hibernate |
spring-boot-starter-jdbc | JDBC với connection pool HikariCP |
spring-boot-starter-security | Spring Security |
spring-boot-starter-validation | Java Bean Validation với Hibernate Validator |
spring-boot-starter-actuator | các endpoint sẵn sàng cho production để monitor và quản lý |
spring-boot-starter-thymeleaf | template HTML render phía server |
spring-boot-starter-restclient | các HTTP client blocking — RestClient, RestTemplate, HTTP service client |
spring-boot-starter-cache | lớp cache abstraction của Spring |
spring-boot-starter-test | JUnit Jupiter, Hamcrest và Mockito, đã ghép sẵn cho Spring |
Có một quy ước đặt tên đáng nhớ, vì nhìn vào là biết ai đang maintain một dependency. spring-boot-starter-* được dành riêng cho starter do team Spring publish. Bên thứ ba thì đặt tên mình lên trước: mybatis-spring-boot-starter, mybatis-plus-spring-boot3-starter. Nếu có lúc nào bạn publish một starter, hãy theo đúng quy ước đó — một coordinate mở đầu bằng spring-boot-starter- là đang tự nhận mình chính chủ.
Các version number đến từ đâu?
Nhìn lại khối dependency ở trên: không có một version nào. Đó không phải Boot plugin làm gì thông minh lúc runtime, mà là một bill of materials — một POM có nhiệm vụ duy nhất là tuyên bố "nếu bạn dùng artifact này thì dùng version này". spring-boot-dependencies:4.1.1 quản 652 dependency qua 195 version property.
Bên Gradle, nó được áp bởi plugin io.spring.dependency-management, cái mà Initializr đặt sẵn trong build file cạnh Boot plugin:
plugins {
id 'java'
id 'org.springframework.boot' version '4.1.1'
id 'io.spring.dependency-management' version '1.1.7'
}Hai plugin này làm hai việc khác nhau, đừng nhầm. Boot plugin build ra executable jar và dựng task bootRun. Plugin dependency-management import BOM để những coordinate không có version resolve được. Xoá dòng thứ hai đi là build chết ngay:
* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Could not find org.springframework.boot:spring-boot-starter-webmvc:.
Required by:
root project 'demo'Dấu hai chấm cuối câu không có gì đứng sau chính là version rỗng — Gradle hỏi version, mà BOM thì không có ở đó để trả lời.
Thứ BOM mang lại là sự đồng bộ, chứ không chỉ là tiện. Một nửa số jar trên classpath 39 jar kia mang version mà bạn chưa gõ ở đâu cả:
| Artifact | Version | Đến từ đâu |
|---|---|---|
tomcat-embed-core | 11.0.24 | tomcat.version trong BOM |
logback-classic | 1.5.38 | logback.version trong BOM |
jackson-databind | 3.1.5 | jackson-bom.version trong BOM |
snakeyaml | 2.6 | snakeyaml.version trong BOM |
slf4j-api | 2.0.18 | slf4j.version trong BOM |
Chỗ thấy rõ nhất tác dụng của sự đồng bộ là khi hai thư viện không thống nhất. spring-webmvc:7.0.9 khai phụ thuộc vào micrometer-observation:1.16.7. Ở build thuần, bạn nhận đúng con số đó. Dưới Boot, BOM nâng nó lên và Gradle in ra phép thay thế:
io.micrometer:micrometer-observation:1.16.7 -> 1.17.1Không ai yêu cầu 1.17.1 cả. BOM quyết định đó mới là bản Micrometer mà toàn bộ Boot 4.1.1 đã được test cùng, và giờ mọi module trên classpath đều thống nhất ở đó. Làm việc này bằng tay trên 652 artifact chính là phần công sức mà Boot đang tiết kiệm cho bạn.
Auto-configuration thực sự làm gì
Ý tưởng gọn đến mức nói được trong một câu: lúc khởi động, Boot nhìn xem có gì trên classpath và trong config của bạn, rồi tạo ra những bean mà một application thông thường lẽ ra phải tự tạo — nhưng chỉ khi bạn chưa tạo chúng.
Phần khiến nó dùng được là cơ chế nhường chỗ. Các class auto-configuration canh bean của mình bằng @ConditionalOnMissingBean, nên ngay khi bạn khai một bean cùng type, bản của Boot lặng lẽ lùi lại và bản của bạn thắng. Không có gì phải disable, không có cuộc chiến nào phải thắng; khai bean chính là cách override.
Chạy application với --debug sẽ in ra một CONDITIONS EVALUATION REPORT liệt kê từng quyết định. Trên project trần này, nó báo 52 match dương và 39 match âm, trong đó có cái đăng ký đúng servlet mà class WebInit ngày xưa phải tự đăng ký:
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class
'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)Đọc kỹ report đó — và cả họ annotation @Conditional* đứng sau nó — là nội dung của riêng một chương, và series này sẽ tới đó sau. Còn bây giờ, mô hình đủ dùng là: classpath vào, bean ra, và thứ gì bạn tự khai thì thứ đó được ưu tiên.
Embedded server hay WAR: hai hình dạng deploy
Cách deploy Spring cổ điển tạo ra một WAR mà bạn copy vào một servlet container do người khác cài và vận hành. Boot lật ngược quan hệ chứa: build tạo ra một jar duy nhất, và chính jar đó chứa server.

Cái jar đó tự chứa thật sự. Manifest của nó trỏ vào launcher của Boot chứ không phải class của bạn, và bố cục lồng nhau bên trong là chuẩn:
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.example.demo.DemoApplication
Spring-Boot-Version: 4.1.1
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/BOOT-INF/lib/ chứa 35 jar, trong đó có tomcat-embed-core-11.0.24.jar, và cả artifact nặng 19.0 MiB. Chạy nó chỉ cần một JVM, không cần gì thêm:
java -jar build/libs/demo-0.0.1-SNAPSHOT.jarINFO 12815 --- [demo] [main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
INFO 12815 --- [demo] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.24]
INFO 12815 --- [demo] [main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
INFO 12815 --- [demo] [main] com.example.demo.DemoApplication : Started DemoApplication in 0.561 seconds (process running for 0.744)Con số thời gian khởi động đó chỉ mang tính tham khảo — máy dev với cache đã nóng, không phải một benchmark.
Còn đây là những gì thực sự thay đổi giữa hai hình dạng:
| WAR trong container bên ngoài | Executable jar | |
|---|---|---|
| Version của server | do người vận hành server chọn và vá | ghim trong build file, đi theo artifact |
| Config của server | server.xml, áp cho cả container | application.properties, riêng từng application |
| Lệnh khởi động | script riêng của container | java -jar app.jar |
| Port | của container, dùng chung cho mọi app đã deploy | của bạn, mỗi application một process |
| Test | cần một container, hoặc một bản mock | server thật chạy in-process trên một port ngẫu nhiên |
| Phạm vi ảnh hưởng khi hỏng | một app lỗi có thể kéo sập hàng xóm | một process, một application |
Đổi embedded server
Tomcat là mặc định vì spring-boot-starter-webmvc kéo theo spring-boot-starter-tomcat. Exclude nó ra rồi thêm cái khác vào:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
implementation 'org.springframework.boot:spring-boot-starter-jetty'
}Không sửa code, không sửa config. Cũng application đó khởi động trên Jetty:
INFO 14295 --- [demo] [main] org.eclipse.jetty.server.Server : Started oejs.Server@799ed4e8{STARTING}[12.1.12,sto=0] @44ms
INFO 14295 --- [demo] [main] o.s.boot.jetty.JettyWebServer : Jetty started on port 8080 (http/1.1) with context path '/'Một đính chính cho gần như mọi bài viết về chủ đề này: Boot 4 không còn starter cho Undertow. spring-boot-starter-undertow có đến 3.5.x và biến mất khỏi 4.x — nó không nằm trong BOM spring-boot-dependencies:4.1.1, và coordinate đó trả về 404 trên Maven Central. Trên Boot 4, embedded servlet container chỉ còn Tomcat và Jetty, cộng thêm Reactor Netty cho stack reactive.
Nếu vẫn buộc phải ship WAR
Boot vẫn hỗ trợ. Yêu cầu Initializr packaging=war thì project sinh ra sẽ thêm plugin war, chuyển container sang providedRuntime để nó không bị gói vào archive, và kèm thêm một class initializer nhỏ:
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '4.1.1'
id 'io.spring.dependency-management' version '1.1.7'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat-runtime'
}public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WarpApplication.class);
}
}Class đó chính là hậu duệ hiện đại của WebApplicationInitializer ở phần đầu bài — container bên ngoài tìm thấy nó, rồi nó trao quyền lại cho Boot.
Hệ sinh thái Spring mà bạn sẽ gặp
"Spring" là cái ô che cho hàng chục project. Đây là những cái mà một developer đi làm sẽ đụng tới, kèm version mà BOM của Boot 4.1.1 quản:
| Project | Dùng để làm gì | Version dưới Boot 4.1.1 |
|---|---|---|
| Spring Framework | container, DI, AOP, transaction, web stack | 7.0.9 |
| Spring Boot | starter, auto-configuration, embedded server, BOM | 4.1.1 |
| Spring Data | lớp repository abstraction cho JPA, MongoDB, Redis, JDBC và nhiều loại khác | BOM 2026.0.1 |
| Spring Security | authentication, authorization, OAuth2, method security | 7.1.1 |
| Spring Batch | batch job theo chunk, có restart và retry | 6.0.5 |
| Spring Integration | các enterprise integration pattern dưới dạng message channel | 7.1.1 |
| Spring for Apache Kafka | producer, consumer và listener container cho Kafka | 4.1.1 |
| Spring AMQP | cũng vậy nhưng cho RabbitMQ | 4.1.1 |
| Spring GraphQL | một endpoint GraphQL đặt trên web stack của Spring | 2.0.5 |
| Spring Session | lưu HTTP session vào Redis hoặc JDBC thay vì trong server | 4.1.1 |
| Spring Web Services | SOAP contract-first, nơi nào bạn còn cần tới | 5.0.2 |
| Spring Cloud | config server, service discovery, gateway, resilience | BOM riêng |
| Spring AI | model client, embedding, vector store, phần khung cho RAG | BOM riêng |
| Spring Modulith | ép ranh giới module bên trong một deployable | BOM riêng |
Ba cái cuối đáng nhắc riêng: Spring Cloud, Spring AI và Spring Modulith không nằm trong BOM của Boot. Mỗi cái publish BOM riêng, và bạn import nó song song với BOM của Boot rồi khớp release train với version Boot đang dùng. Mọi thứ phía trên chúng thì đi kèm sẵn theo version Boot bạn đã chọn.
Khi nào Spring Boot không phải là câu trả lời
Boot là một mặc định, không phải luật, và những lựa chọn mặc định của nó cũng có giá.
- Một thư viện để người khác nhúng vào. Nếu artifact của bạn là một dependency chứ không phải một thứ để deploy, thì fat jar và auto-configuration là sai hình dạng. Hãy publish một jar thường, dùng Spring Framework thuần hoặc không framework nào cả.
- Một script chạy một lần. Ba mươi chín jar và một artifact 19 MiB chỉ để parse một file CSV là cái giá không đáng.
- Một hạ tầng application server dùng chung. Nếu bộ phận vận hành chạy cả một farm Tomcat và bắt buộc deploy WAR vào đó, bạn vẫn dùng Boot được, nhưng mất đi phần đơn giản hoá deploy vốn là điểm cộng lớn nhất.
- Một application Spring Framework đang chạy tốt. Chuyển một hệ thống XML cũ, ổn định sang Boot tự nó không mang lại gì. Hãy chuyển khi bạn vốn đã phải sửa nó rồi.
- Trần cứng về thời gian khởi động hoặc bộ nhớ. Quét classpath và reflection không miễn phí. Boot có AOT processing và GraalVM native image cho chuyện này, nhưng nếu bạn đang giành giật từng chục mili giây thì một framework nhỏ hơn có thể hợp hơn.
Với một application phía server do chính bạn sở hữu và deploy — tức là phần lớn những gì được viết ra — cán cân nghiêng hẳn về phía Boot, và đó là lý do phần còn lại của series này mặc định dùng nó.
Câu hỏi thường gặp
Spring Boot có thay thế Spring Framework không?
Không. Boot phụ thuộc vào Framework và không thể tồn tại thiếu nó. Boot 4.1.1 kéo về Framework 7.0.9, và mọi bean, mọi annotation cùng toàn bộ container đều là code của Framework. Boot chỉ quyết định cái gì được config sẵn.
Có dùng Spring Framework mà không dùng Spring Boot được không?
Được, và vẫn được hỗ trợ đầy đủ. Bạn khai thẳng spring-webmvc hoặc spring-context, tự chọn từng version, và tự viết các class config. Cái tree ở trên cho thấy trọn cái giá: mười một jar cho MVC stack, còn server, JSON và logging thì bạn tự thêm.
Vì sao là spring-boot-starter-webmvc chứ không phải spring-boot-starter-web?
Boot 4 chia module mịn hơn và đổi tên web starter để nói rõ nó là web stack nào, vì spring-boot-starter-webflux là lựa chọn còn lại. spring-boot-starter-web vẫn resolve được trên 4.1.1 và cho ra đúng 39 jar y hệt — khác biệt duy nhất trên classpath đã resolve là tên của chính file jar starter — nhưng POM của chính nó đánh dấu deprecated và trỏ sang spring-boot-starter-webmvc.
Auto-configuration có làm mình mất quyền kiểm soát không?
Không — nó được thiết kế để chịu thua. Bean do auto-configuration tạo ra đều được canh bằng @ConditionalOnMissingBean, nên khai một bean cùng type là bản của Boot biến mất. Bạn cũng có thể exclude hẳn một class auto-configuration, và --debug sẽ in ra report về cái gì đã match và cái gì không.
Embedded server có dùng được cho production không?
Có. Nó chính là Apache Tomcat 11.0.24 mà bạn sẽ cài standalone, chỉ khác là khởi động in-process thay vì bằng script. Khác biệt thực tế nằm ở khâu vận hành — mỗi application một process, config nằm trong application.properties, và version của server do build của bạn ghim chứ không do người vá server quyết định.
Làm sao biết Spring Boot sẽ cho mình version nào của một thư viện?
Đọc spring-boot-dependencies của bản Boot đang dùng, hoặc hỏi thẳng build. ./gradlew dependencies --configuration runtimeClasspath in ra cây đã resolve với mọi phép thay thế được đánh dấu bằng mũi tên, và đó chính là cách tìm ra phép nâng micrometer-observation:1.16.7 -> 1.17.1 ở trên.
Kết luận
Khác biệt giữa Spring Framework và Spring Boot không phải một danh sách tính năng, mà là một cách chia việc. Framework chạy bean của bạn; Boot quyết định một application bình thường cần những bean nào, ghim mọi version đi kèm, rồi đóng gói kết quả với một server nằm sẵn bên trong. Một dòng starter, bốn dependency, 39 jar, và một DispatcherServlet bạn chưa từng đăng ký.
Bài tiếp theo: cài đặt môi trường — cài JDK và IDE, tạo project bằng Spring Initializr, và chạy ứng dụng Hello World đầu tiên.