<?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>
<groupId>org.springframework</groupId>
<artifactId>gs-multi-module</artifactId>
<version>0.1.0</version>
<packaging>pom</packaging>
<modules>
<module>library</module>
<module>application</module>
</modules>
</project>
建立多模組專案
本指南向您展示如何使用 Spring Boot 建立一個多模組專案。該專案將包含一個庫 Jar 包和一個使用該庫的主應用程式。您也可以使用它來了解如何單獨構建一個庫(即,不是應用程式的 Jar 檔案)。
您將構建什麼
您將設定一個庫 Jar 包,該 Jar 包提供一個用於簡單“Hello, World”訊息的服務,然後將該服務包含在一個使用該庫作為依賴項的 Web 應用程式中。
你需要什麼
如何完成本指南
與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,也可以跳過您已熟悉的基本設定步驟。無論哪種方式,您最終都會得到可工作的程式碼。
要從頭開始,請繼續閱讀建立根專案。
要跳過基礎知識,請執行以下操作
-
下載並解壓本指南的原始碼倉庫,或者使用 Git 克隆:
git clone https://github.com/spring-guides/gs-multi-module.git -
cd 到
gs-multi-module/initial -
跳到建立庫專案。
完成後,您可以將結果與 gs-multi-module/complete 中的程式碼進行比較。
首先,您需要設定一個基本的構建指令碼。在使用 Spring 構建應用程式時,您可以使用任何您喜歡的構建系統,但這裡包含了與 Gradle 和 Maven 協作所需的程式碼。如果您不熟悉其中任何一個,請參閱 使用 Gradle 構建 Java 專案 或 使用 Maven 構建 Java 專案。
建立根專案
本指南將引導您構建兩個專案,其中一個專案是另一個專案的依賴項。因此,您需要在根專案下建立兩個子專案。但首先,在頂層建立構建配置。對於 Maven,您需要一個 pom.xml,其中 <modules> 列出了子目錄
對於 Gradle,您需要一個 settings.gradle,其中包含相同的目錄
rootProject.name = 'gs-multi-module' include 'library' include 'application'
並且(可選)您可以包含一個空的 build.gradle(以幫助 IDE 識別根目錄)。
建立目錄結構
在您想要作為根目錄的目錄中,建立以下子目錄結構(例如,在 *nix 系統上使用 mkdir library application)
└── library └── application
在專案的根目錄中,您需要設定一個構建系統,本指南將向您展示如何使用 Maven 或 Gradle。
建立庫專案
這兩個專案中的一個作為其他專案(應用程式)將使用的庫。
建立目錄結構
在 library 目錄中,建立以下子目錄結構(例如,在 *nix 系統上使用 mkdir -p src/main/java/com/example/multimodule/service)
└── src
└── main
└── java
└── com
└── example
└── multimodule
└── service
現在您需要配置一個構建工具(Maven 或 Gradle)。在這兩種情況下,請注意 Spring Boot 外掛在庫專案中完全沒有使用。該外掛的主要功能是建立一個可執行的“über-jar”,而我們既不需要也不想要一個庫。
儘管沒有使用 Spring Boot Maven 外掛,但您確實希望利用 Spring Boot 依賴管理,因此透過使用 Spring Boot 的 spring-boot-starter-parent 作為父專案來配置它。另一種方法是將依賴管理作為物料清單 (BOM) 匯入到 pom.xml 檔案的 <dependencyManagement/> 部分。
設定庫專案
對於庫專案,您無需新增依賴項。基本的 spring-boot-starter 依賴項提供了您所需的一切。
您可以直接從 Spring Initializr 獲取包含必要依賴項的 Maven 構建檔案。以下列表顯示了選擇 Maven 時建立的 pom.xml 檔案
<?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.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>library</artifactId> <version>0.0.1-SNAPSHOT</version> <name>library</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</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>
您可以直接從 Spring Initializr 獲取包含必要依賴項的 Gradle 構建檔案。以下列表顯示了選擇 Gradle 時建立的 build.gradle 檔案
plugins {
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
調整庫專案
如果您是從 start.spring.io 生成的庫專案,它將包含一個用於構建系統的包裝指令碼(根據您的選擇,可能是 mvnw 或 gradlew)。您可以將該指令碼及其相關的配置移到根目錄
$ mv mvnw* .mvn ..
$ mv gradlew* gradle ..
最好是庫依賴於最窄的依賴項,而不是啟動器。對於我們自己的使用,org.springframework.boot:spring-boot 包含了我們所需的所有程式碼。刪除現有條目的 -starter 可確保庫不會引入過多的依賴項。
庫專案沒有帶有 main 方法的類(因為它不是一個應用程式)。因此,您必須告訴構建系統不要嘗試為庫專案構建可執行 jar。(預設情況下,Spring Initializr 會構建可執行專案。)
為了告訴 Maven 不為庫專案構建可執行 jar,您必須從 Spring Initializr 建立的 pom.xml 中刪除以下程式碼塊
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
以下列表顯示了庫專案的最終 pom.xml 檔案
<?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.2.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>library</artifactId> <version>0.0.1-SNAPSHOT</version> <name>library</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
為了告訴 Gradle 不為庫專案構建可執行 jar,您必須將以下程式碼塊新增到 Spring Initializr 建立的 build.gradle 中
plugins {
id 'org.springframework.boot' version '3.2.2' apply false
id 'io.spring.dependency-management' version '1.1.4'
// ... other plugins
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
bootJar 任務嘗試建立一個可執行 jar,這需要一個 main() 方法。因此,您需要透過停用 Spring Boot 外掛來停用它,同時保留其依賴管理功能。
此外,既然我們已經停用了 Spring Boot 外掛,它就不再自動配置 JavaCompiler 任務以啟用 -parameters 選項。如果您使用引用引數名稱的表示式,這一點很重要。以下啟用此選項
tasks.withType(JavaCompile).configureEach {
options.compilerArgs.add("-parameters")
}
以下列表顯示了庫專案的最終 build.gradle 檔案
plugins {
id 'org.springframework.boot' version '3.3.0' apply false
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.withType(JavaCompile).configureEach {
options.compilerArgs.add("-parameters")
}
建立服務元件
該庫將提供一個可供應用程式使用的 MyService 類。以下列表(來自 library/src/main/java/com/example/multimodule/service/MyService.java)顯示了 MyService 類
package com.example.multimodule.service;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
@Service
@EnableConfigurationProperties(ServiceProperties.class)
public class MyService {
private final ServiceProperties serviceProperties;
public MyService(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public String message() {
return this.serviceProperties.getMessage();
}
}
為了以標準的 Spring Boot 方式(使用 application.properties)使其可配置,您還可以新增一個 @ConfigurationProperties 類。ServiceProperties 類(來自 library/src/main/java/com/example/multimodule/service/ServiceProperties.java)滿足了這一需求
package com.example.multimodule.service;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("service")
public class ServiceProperties {
/**
* A message for the service.
*/
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
您不必這樣做。一個庫可能僅僅提供純 Java API,而不提供 Spring 功能。在這種情況下,使用該庫的應用程式需要自己提供配置。
測試服務元件
您將需要為您的庫元件編寫單元測試。如果您提供可重用的 Spring 配置作為庫的一部分,您可能還需要編寫一個整合測試,以確保配置正常工作。為此,您可以使用 JUnit 和 @SpringBootTest 註解。以下列表(來自 library/src/test/java/com/example/multimodule/service/MyServiceTest.java)顯示瞭如何實現
package com.example.multimodule.service;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest("service.message=Hello")
public class MyServiceTest {
@Autowired
private MyService myService;
@Test
public void contextLoads() {
assertThat(myService.message()).isNotNull();
}
@SpringBootApplication
static class TestConfiguration {
}
}
在前面的列表中,我們透過使用 @SpringBootTest 註解的預設屬性為測試配置了 service.message。我們不建議在庫中放置 application.properties,因為在執行時可能會與使用該庫的應用程式發生衝突(類路徑中只會載入一個 application.properties)。您可以將 application.properties 放置在測試類路徑中,但不將其包含在 jar 中(例如,透過將其放置在 src/test/resources 中)。 |
建立應用程式專案
應用程式專案使用庫專案,該庫專案提供其他專案可以使用的服務。
建立目錄結構
在 application 目錄中,建立以下子目錄結構(例如,在 *nix 系統上使用 mkdir -p src/main/java/com/example/multimodule/application)
└── src
└── main
└── java
└── com
└── example
└── multimodule
└── application
不要使用與庫相同的包(或庫包的父包),除非您希望透過應用程式中的 @ComponentScan 包含庫中的所有 Spring 元件。
設定應用程式專案
對於應用程式專案,您需要 Spring Web 和 Spring Boot Actuator 依賴項。
您可以直接從 Spring Initializr 獲取包含必要依賴項的 Maven 構建檔案。以下列表顯示了選擇 Maven 時建立的 pom.xml 檔案
<?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.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>application</artifactId> <version>0.0.1-SNAPSHOT</version> <name>application</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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>
您可以直接從 Spring Initializr 獲取包含必要依賴項的 Gradle 構建檔案。以下列表顯示了選擇 Gradle 時建立的 build.gradle 檔案
plugins {
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
您可以刪除 mvnw 和/或 gradlew 包裝器及其相關的配置檔案
$ rm -rf mvnw* .mvn
$ rm -rf gradlew* gradle
新增庫依賴
應用程式專案需要依賴庫專案。您需要相應地修改您的應用程式構建檔案。
對於 Maven,新增以下依賴項
<dependency>
<groupId>com.example</groupId>
<artifactId>library</artifactId>
<version>${project.version}</version>
</dependency>
以下列表顯示了已完成的 pom.xml 檔案
<?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.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>application</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>library</artifactId>
<version>${project.version}</version>
</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>
對於 Gradle,新增以下依賴項
implementation project(':library')
以下列表顯示了最終的 build.gradle 檔案
plugins {
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation project(':library')
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
編寫應用程式
應用程式中的主類可以是一個 @RestController,它使用庫中的 Service 來呈現訊息。以下列表(來自 application/src/main/java/com/example/multimodule/application/DemoApplication.java)顯示了這樣一個類
package com.example.multimodule.application;
import com.example.multimodule.service.MyService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication(scanBasePackages = "com.example.multimodule")
@RestController
public class DemoApplication {
private final MyService myService;
public DemoApplication(MyService myService) {
this.myService = myService;
}
@GetMapping("/")
public String home() {
return myService.message();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication 是一個方便的註解,它添加了以下所有內容
-
@Configuration:將類標記為應用程式上下文的 bean 定義源。 -
@EnableAutoConfiguration:告訴 Spring Boot 根據類路徑設定、其他 bean 和各種屬性設定開始新增 bean。例如,如果spring-webmvc在類路徑中,此註解會將應用程式標記為 Web 應用程式並激活關鍵行為,例如設定DispatcherServlet。 -
@ComponentScan:告訴 Spring 在com/example包中查詢其他元件、配置和服務,使其能夠找到控制器。
main() 方法使用 Spring Boot 的 SpringApplication.run() 方法啟動應用程式。您是否注意到沒有一行 XML?也沒有 web.xml 檔案。這個 Web 應用程式是 100% 純 Java,您不必處理任何管道或基礎設施的配置。
由於 DemoApplication 位於與 MyService (com.example.multimodule.service) 不同的包 (com.example.multimodule.application) 中,@SpringBootApplication 無法自動檢測到它。有不同的方法可以讓 MyService 被識別
-
使用
@Import(MyService.class)直接匯入它。 -
使用
@SpringBootApplication(scanBasePackageClasses={…})從其包中獲取所有內容。 -
按名稱指定父包:
com.example.multimodule。(本指南使用此方法)
如果您的應用程式也使用 JPA 或 Spring Data,則在未明確指定時,@EntityScan 和 @EnableJpaRepositories(以及相關的)註解僅從 @SpringBootApplication 繼承其基本包。也就是說,一旦您指定了 scanBasePackageClasses 或 scanBasePackages,您可能還需要顯式使用 @EntityScan 和 @EnableJpaRepositories 並明確配置其包掃描。 |
建立 application.properties 檔案
您需要在 application.properties 中為庫中的服務提供一條訊息。在原始檔夾中,您需要建立一個名為 src/main/resources/application.properties 的檔案。以下列表顯示了一個可以正常工作的檔案
service.message=Hello, World
測試應用程式
透過啟動應用程式來測試端到端結果。您可以在 IDE 中啟動應用程式,或使用命令列。應用程式執行後,在瀏覽器中訪問客戶端應用程式,地址為 https://:8080/。在那裡,您應該在響應中看到 Hello, World。
如果您使用 Gradle,以下命令(實際上是按順序執行的兩個命令)將首先構建庫,然後執行應用程式
$ ./gradlew build && ./gradlew :application:bootRun
如果您使用 Maven,以下命令(實際上是按順序執行的兩個命令)將首先構建庫,然後執行應用程式
$ ./mvnw install && ./mvnw spring-boot:run -pl application
總結
恭喜!您已經使用 Spring Boot 建立了一個可重用庫,然後使用該庫構建了一個應用程式。