Spring 核心有兩個技術:IoC (Invertion of Control) 控制反轉 與 AOP (Aspect Oriented Programming)
IoC 就是以 DI (Dependency Injection) 實現,不修改程式就能把某一個變數所參考到的物件換成某一個相容的物件。
AOP 就是以 proxy design pattern 區分商業與一般業務邏輯,讓開發者更聚焦商業邏輯的開發,一般業務邏輯例如使用者權限檢查、資料庫交易 transaction,或是 log 記錄,這些重複的通用功能。很像是將 business logic functions 以橫切面的方式,加上一般業務邏輯的一些通用功能。
Spring Boot 以 Convention over Configuration 的概念,減少大量設定,只需要定義預設以外的設定。
核心模組
spring-boot
這是 Spring Boot 最主要的模組,主要功能:
啟動 Spring application 的主類別,有靜態 method 能產生 Spring container 的 context
提供內嵌可自由搭配的 servlet container,例如 Tomcat, Jetty, Undertow
spring-boot-autoconfigure
常用的自動設定模組,可用
@EnableAutoConfiguration
來做自動設定spring-boot-starters
這是所有 starter 的基礎
spring-boot-cli
CLI 工具,這也是產生 spring application 的方法
spring-boot-actuator
application 監控模組
spring-boot-actuator-autoconfigure
為 spring-boot-actuator 提供自動設定的模組
spring-boot-test
測試模組
spring-boot-test-autoconfigure
為 spring-boot-test 提供自動設定的模組
spring-boot-loader
可將 spring boot application 打包成一個可單獨執行的 jar,用
java -jar
執行spring-boot-devtools
開發者工具,用在 application 的開發階段。ex: 修改程式可自動重新啟動 application。打包後會自動被禁用。
spring-boot-starter-web 依賴於 spring-webmvc,spring-webmvc 依賴於 spring-beans, spring-core。
Spring Cloud - Spring Boot - Spring MVC - Spring 這四個由上到下的關係
版本
GA (General Availability) 正式版
Current:最新的 GA 正式版
SNAPSHOT:最新的變更,每天編譯的版本
PRE:預覽版
Milestore:例如 3.0.0-M3
Release Candidate RC:例如 3.0.0-RC2
系統需求
ref: System Requirements :: Spring Boot
Spring Boot 3.3.5 的開發環境需求
JDK 17+
Spring 6.1.14+
Maven 3.6.3+
Gradle 7.5+, 8.x
Servlet Container 的版本,必須要是 servlet 5+ 相容的 container
Tomcat 10+
Jetty 11+
Undertow 2.2+
Spring Boot application 可透過 GraalVM 22.3+ 的 native-image tool 或是 Gradle/Maven 的 native build tools plugins 被轉換為 Native Image。
GraalVM Community 22.3
Native Build Tools 0.10.3
Demo Project
到網站 https://start.spring.io/ 可產生 Spring Boot 的專案
原本預設右邊 Dependencies 是空的,這邊因為要開發一個簡單的 web service,所以加上 Spring Web library。Package 方式有兩種,jar 跟 war,jar 是可以直接執行的,war 必須放到一個 Servlet container 裡面執行,這邊是最後封裝的結果,開發時還是用單獨的 application 執行。
產生的專案,用 Generate 可下載到 zip,解壓縮後,用 IDE 打開
pom.xml 裡面因為 web dependencies 的關係,多了 spring-boot-starter-web 與 spring-boot-starter-tomcat,因封裝方式為 war,所以 spring-boot-starter-tomcat 必須標記 provided
<?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>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>tw.com.test</groupId>
<artifactId>demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>demo1</name>
<description>Test project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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
專案中有 mvnw 的 script,這是 maven wrapper。mvnw 只是 mvn 的封裝,指令參數一樣,如果有自己安裝了 maven,就不需要使用 mvnw。
修改 Demo1Application.java
package tw.com.test.demo1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
@RequestMapping("/hello")
public String helloWorld() {
return "hello world";
}
}
加上 @RestController 以及 @RequestMapping("/hello") 這兩個部分。
專案中還有一個 ServletInitializer.java,這是因為 packaging 方式設定為 war 才有的。
啟動方式,可在 IDE 裡面執行 Demo1Application,或是在 console 用以下方式啟動
$ mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< tw.com.test:demo1 >--------------------------
[INFO] Building demo1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.3.5:run (default-cli) > test-compile @ demo1 >>>
[INFO]
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ demo1 ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO] Copying 0 resource from src/main/resources to target/classes
[INFO]
[INFO] --- maven-compiler-plugin:3.13.0:compile (default-compile) @ demo1 ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 2 source files with javac [debug parameters release 17] to target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.3.1:testResources (default-testResources) @ demo1 ---
[INFO] skip non existing resourceDirectory /Users/charley/project/idea/book/test/demo1/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.13.0:testCompile (default-testCompile) @ demo1 ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 1 source file with javac [debug parameters release 17] to target/test-classes
[INFO]
[INFO] <<< spring-boot-maven-plugin:3.3.5:run (default-cli) < test-compile @ demo1 <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:3.3.5:run (default-cli) @ demo1 ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.3.5)
啟動後,可在 browser 瀏覽 http://localhost:8080/hello ,會看到網頁內容是 "hello world"
Spring Boot CLI
Spring Boot Command Line Interface 可跟 start.spring.io 一樣,產生一個新的 spring boot project,或是用來加密。
該工具是用打包在一起的 Groovy 實作。直接從 Installing Spring Boot :: Spring Boot 下載壓縮檔後,解壓縮,需要設定 SPRING_HOME
環境變數,以及 PATH要增加 $SPRING_HOME/bin
。
Spring Boot CLI 提供在 bash/zsh 自動補上指令的功能。
ln -s ./shell-completion/bash/spring /etc/bash_completion.d/spring
ln -s ./shell-completion/zsh/_spring /usr/local/share/zsh/site-functions/_spring
RestController vs Controller
RestController 是處理 RESTful Web method,通常用在頁面裡面的資料JSON 或 XML。
Controller 是傳統的 html/jsp 網頁,在 Spring Boot 可搭配 thymeleaf template engine 使用。
在剛剛的 Demo Project 裡面,修改 XML 增加 thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
新增 Test.java
package tw.com.test.demo1.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class Test {
@GetMapping("/test")
public String test(HttpServletRequest request) {
request.setAttribute("name", "UserName");
// "test" 會映射到 Thymeleaf templates/test.html
return "test";
}
}
新增 resources/templates/test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf Template</title>
</head>
<body>
<span th:text="${name}" /> ,Spring Boot!
</body>
</html>
啟動測試後,http://localhost:8080/hello 會看到 hello world 網頁內容。
http://localhost:8080/test 會看到 UserName ,Spring Boot! 網頁內容
IDE Plugin
如果是使用 Eclipse,可安裝 Spring Tool Suite (STS) plugin,該 plugin 有跟網站 https://start.spring.io/ 一樣的功能,可產生 Spring Boot 的專案
如果是使用 IDEA,在 New Project 可選擇 Spring Initializer,也有類似的功能。