包含嵌套Maven项目的Spring Boot项目称为 多模块项目。在多模块项目中,父项目充当基础Maven配置的容器。
换句话说, 多模块项目是从管理一组子模块的父pom构建的。或 多模块项目由父POM引用一个或多个子模块来定义。
父maven项目必须包含 pom 的包装类型使该项目成为聚合器。父项目的 pom.xml 文件包含子项目继承的所有 模块,公共依赖项和 属性的列表。父pom位于项目的根目录中。子模块是实际的Spring Boot项目,它们从父项目继承maven属性。
当我们运行多模块项目时,所有模块都一起部署在嵌入式Tomcat Server中。我们也可以部署单个模块。
父POM定义了 组ID,工件ID,版本,和 packaging。。在以前的Maven项目中,我们已经看到父级POM定义了包装 jar。。但是在多模块项目中,父级 POM 定义包装pom。打包pom引用了其他Maven项目。
将项目分为多个模块是有用且易于维护的。我们还可以轻松编辑或删除项目中的模块,而不会影响其他模块。当我们需要分别部署模块时,这很有用。
我们只需要在父pom中指定所有依赖项即可。所有其他模块共享相同的pom,因此我们无需在每个模块中分别指定相同的依赖项。
子模块可以是任何项目,并且可以有任何包装。我们可以自由地在模块和束之间创建任何类型的依赖关系。
例如,我们正在创建 EAR (企业归档), WAR (Web ARchive)和 JAR (Java ARchive)文件。 JAR文件捆绑到war文件中,而war文件捆绑到EAR文件中。 EAR文件是可以在应用程序服务器上部署的最终软件包。
EAR文件包含一个或多个WAR文件。每个WAR文件都包含服务项目,该项目对JAR中的所有WAR文件和打包类型具有通用代码。
子模块是独立的maven项目,它们共享父项目的属性。 所有子项目都可以用一个命令来构建,因为它位于父项目中。 定义项目之间的关系更容易。
让我们了解多模块项目目录结构。
在下图中,我们创建了一个名为 spring-boot-multi-module-project 的项目。它在目录底部包含父 pom 。之后,我们创建了两个 Maven模块,分别命名为 module1 和 module2 。这两个模块包含自己的pom文件。
让我们打开父POM,并查看在项目中创建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>2.2.2.BUILD-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.nhooo</groupId> <artifactId>spring-boot-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-multi-module-project</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <packaging>pom</packaging> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> <modules> <module>module1</module> <module>module2</module> </modules> </project>
上面的pom文件与前面的示例相同。但是在此 pom 文件中,需要注意两件事: 包装和 模块。
当我们创建多模块时项目,我们需要在父pom文件中配置打包pom,而不是 jar。
<packaging>pom</packaging>
当我们在项目中创建Maven模块时,Spring Boot会在 module 标签内的父pom中自动配置模块,如下所示。
<modules> <module>module1</module> <module>module2</module> </modules>
现在,我们将查看 module1的pom文件中的内容。
pom.xml
<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.nhooo</groupId> <artifactId>spring-boot-multi-module-project</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.nhooo</groupId> <artifactId>module1</artifactId> <version>0.0.1-SNAPSHOT</version> <name>module1</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
在此处,需要注意的是,上述pom文件不包含诸如 starter-web,web-mvc等之类的公共依赖项。它继承了所有公共依赖项和属性 父pom。
让我们创建一个多模块应用程序示例。
在以下示例中,我们创建了一个名为 spring-boot-multimodule的maven项目。这是主要应用程序。在主应用程序中,我们创建了五个模块,如下所示: 应用 模型 存储库 service-api service-impl
应用程序模块
应用程序模块是项目的主要模块。它包含应用程序类,在其中定义了运行Spring Boot Application所需的main方法。它还包含 应用程序配置属性,控制器,视图和 资源。
应用程序模块包括模型模块,服务实现模块作为包含模型的依赖项模块,存储库模块和服务API模块。
模型模块
模型模块包含 实体和在项目中使用的 Visual Objects 。
存储库模块
存储库模块包含 <在项目中使用的strong> 存储库。它取决于模型模块。
服务API模块
服务API模块包含所有项目 服务。这也取决于模型模块。
服务实现模块
服务实现模块可以实现服务。它取决于存储库模块和服务API模块。
父pom包含所有应用程序模块。它还包括一个以上模块所需的所有常见依赖关系和属性。因为项目已将Spring IO Platform定义为父级,所以没有版本就定义了依赖项。
让我们了解我们创建的多模块应用程序的结构。
Spring-boot-multimodule ├── pom.xml │ └── REDME.adoc ├── application │ ├── pom.xml │ └── src │ └── main │ ├── java │ │ └── sample │ │ └── multimodule │ │ ├── SampleWebJspApplication.java │ │ └── web │ │ └── WelcomeController.java │ └── resources │ ├── application.properties │ └── templates │ └── welcome │ └── show.html ├── model │ ├── pom.xml │ └── src │ └── main │ └── java │ └── sample │ └── multimodule │ └── domain │ └── entity │ └── Account.java | ├── repository │ ├── pom.xml │ └── src │ └── main │ └── java │ └── sample │ └── multimodule │ └── repository │ └── AccountRepository.java ├── service-api │ ├── pom.xml │ └── src │ └── main │ └── java │ └── sample │ └── multimodule │ └── service │ └── api │ ├── AccountNotFoundException.java │ └── AccountService.java └── service-impl ├── pom.xml └── src └── main └── java └── sample └── multimodule └── service └── impl └── AccountServiceImpl.java
步骤1: 创建一个名为 spring-boot-multimodule的 Maven项目。
步骤2: 打开 pom.xml (父pom)文件,并将包装类型 jar 更改为 pom。
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- Springio 平台是生成的应用程序的父应用程序,能够使用 Spring Boot 及其所有缺省配置 --> <parent> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>2.0.1.RELEASE</version> </parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>Parent - Pom Aggregator</name> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- Spring Boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
在上面的pom文件中要注意的一件事是,由于尚未创建Maven模块,因此未配置。现在,我们将如上所述创建一个Maven模块。
步骤3: 创建一个名为 application的 Maven模块 。
步骤4: 打开应用程序模块的 pom.xml 文件,并确保打包类型为 jar。
pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sample.multimodule.application</artifactId> <packaging>jar</packaging> <name>Project Module - Application</name> <dependencies> <!-- Project modules --> <dependency> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule.service.impl</artifactId> <version>${project.version}</version> </dependency> <!-- Spring Boot dependencies --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> <build> <plugins> <!-- Spring Boot plugins --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
步骤5: 创建 主要类。这是要运行的类。
SampleWebJspApplication.java
package sample.multimodule; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.SpringApplication; import org.springframework.boot.orm.jpa.EntityScan; @SpringBootApplication public class SampleWebJspApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SampleWebJspApplication.class, args); } }
步骤6: 在包 smaple.multimodule.web。
下创建一个名称为 WelocameController 的Controller类。
WelcomeController.java
package sample.multimodule.web; import java.util.Date; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import sample.multimodule.domain.entity.Account; import sample.multimodule.service.api.AccountService; @Controller public class WelcomeController { @Value("${application.message:Hello World}") private String message = "Hello World"; @Autowired protected AccountService accountService; @RequestMapping("/") public String welcome(Map<String, Object> model) { //试图获得23号帐户 Account account = accountService.findOne("23"); if(account == null){ //如果创建帐户时出现问题,请返回显示错误状态的视图 model.put("message", "Error getting account!"); model.put("account", ""); return "welcome/show"; } //返回显示23个帐户信息的视图 String accountInfo = "Your account number is ".concat(account.getNumber()); model.put("message", this.message); model.put("account", accountInfo); return "welcome/show"; } @RequestMapping("foo") public String foo(Map<String, Object> model) { throw new RuntimeException("Foo"); } }
第7步: : 在文件夹 src/main/resource下创建一个名为 show.html 的 HTML templates ->welcome。
show.html
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Spring Boot Multimodule</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <div> <b>Message: </b> <span th:text="${message}" /> </div> <div> <b>Your account: </b> <span th:text="${account}" /> </div> </body> </html>
步骤8: 打开 application.properties 文件,将 application message和 thymeleaf缓存配置为 否。
application.properties
#应用程序信息 application.message = Hello User! dummy.type = type-inside-the-war #Spring Thymeleaf 配置 spring.thymeleaf.cache = false
创建上述所有文件后,应用程序模块目录如下所示:
让我们创建第二个模块,即 model。
步骤9: 创建一个 Maven Module,名称为 model。
步骤10: 打开模型的 pom.xml 文件模块,并确保包装类型为 jar。
pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sample.multimodule.model</artifactId> <packaging>jar</packaging> <name>Project Module - Model</name> <description>Module that contains all Entities and Visual Objects to be used in the project. It doesn't have any dependencies. </description> </project>
步骤11: 在包 sample.multimodule.domain.entity。
下创建一个名称为 Account 的类。Account.java
package sample.multimodule.domain.entity; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @Entity public class Account { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String number; private String type; private String creditCardNumber; /** * 创建一个空帐户。 */ public Account() { } /** * 创建新帐户。 * * @param number * the account number * @param id * the account id */ public Account(long id, String number) { this.number = number; this.id = id; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getCreditCardNumber() { return creditCardNumber; } public void setCreditCardNumber(String creditCardNumber) { this.creditCardNumber = creditCardNumber; } }
创建所有上述文件后,模型模块目录如下:
让我们创建 third 模块
步骤12: 创建一个名为 repository的 Maven模块。 strong>
步骤13: 打开应用程序模块的 pom.xml 文件,并确保打包类型为 jar。
pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sample.multimodule.repository</artifactId> <packaging>jar</packaging> <name>Project Module - Repository</name> <description>Module that contains all repositories to be used in the project. Depends of Model Module.</description> <dependencies> <!-- Project modules --> <dependency> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule.model</artifactId> <version>${project.version}</version> </dependency> <!-- Spring Boot dependencies --> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> </dependency> </dependencies> </project>
步骤14: 在包 sample.multimodule.repository
创建一个名称为 AccountRepository 的类。
AccountRepository.java
package sample.multimodule.repository; import org.springframework.data.domain.*; import org.springframework.data.repository.*; import org.springframework.stereotype.Repository; import sample.multimodule.domain.entity.Account; @Repository public interface AccountRepository extends CrudRepository<Account, Long> { Account findByNumber(String number); }
创建上述所有文件后,存储库模块目录如下所示:
让我们创建 第四模块,它是 service-api。
步骤15: 创建一个名为 service-api的 Maven模块。
步骤16 : 打开 <strong应用程序service-api 的> pom.xml 文件,并确保打包类型为 jar。
pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sample.multimodule.service.api</artifactId> <packaging>jar</packaging> <name>Project Module - Service API</name> <description>Module that contains API of all project services. Depends of Model Module.</description> <dependencies> <!-- Project Modules --> <dependency> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule.model</artifactId> <version>${project.version}</version> </dependency> </dependencies> </project>
步骤17: 创建名称为 sample.multimodule.service.api的软件包。
步骤18: 创建一个名称为 AccountNotFoundException的类。如果未找到该帐户,它将处理异常。
AccountNotFoundException.java
package sample.multimodule.service.api; public class AccountNotFoundException extends RuntimeException { private static final long serialVersionUID = -3891534644498426670L; public AccountNotFoundException(String accountId) { super("No such account with id: " + accountId); } }
步骤19: 创建一个名为 AccountService的类。它提供与帐户相关的服务,例如 查找和 创建帐户。
AccountService.java
package sample.multimodule.service.api; import java.util.List; import sample.multimodule.domain.entity.Account; public interface AccountService { /** * 使用提供的帐号查找帐户。 * * @param number The account number * @return The account * @throws AccountNotFoundException if no such account exists. */ Account findOne(String number) throws AccountNotFoundException; /** * Creates a new account. * @param number * @return created account */ Account createAccountByNumber(String number); }
创建上述所有文件之后,service-api模块目录如下所示:
步骤20: 创建一个名为 service-impl的 Maven模块。
步骤21: : 打开应用程序 service-impl 的 pom.xml 文件,并确保包装类型为jar。
pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>sample.multimodule.service.impl</artifactId> <packaging>jar</packaging> <name>Project Module - Service Implementation</name> <description>Module that contains services implementation defined on Service API module. Depends of Repository Module and Service API Module.</description> <dependencies> <!-- Project Modules --> <dependency> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule.repository</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>sample.multimodule</groupId> <artifactId>sample.multimodule.service.api</artifactId> <version>${project.version}</version> </dependency> </dependencies> </project>
步骤22: 在包 sample.multimodule.service.impl。
下创建一个名称为 AccountServiceImpl 的类。AccountServiceImpl.java
package sample.multimodule.service.impl; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import sample.multimodule.domain.entity.Account; import sample.multimodule.repository.AccountRepository; import sample.multimodule.service.api.AccountService; import sample.multimodule.service.api.AccountNotFoundException; @Service public class AccountServiceImpl implements AccountService { @Value("${dummy.type}") private String dummyType; @Autowired private AccountRepository accountRepository; /** * {@inheritDoc} * <p/> * Dummy method for testing purposes. * * @param number The account number. Set 0000 to get an {@link AccountNotFoundException} */ @Override public Account findOne(String number) throws AccountNotFoundException { if(number.equals("0000")) { throw new AccountNotFoundException("0000"); } Account account = accountRepository.findByNumber(number); if(account == null){ account = createAccountByNumber(number); } return account; } @Override public Account createAccountByNumber(String number) { Account account = new Account(); account.setNumber(number); return accountRepository.save(account); } public String getDummyType() { return dummyType; } public void setDummyType(String dummyType) { this.dummyType = dummyType; } }
创建上述所有文件后, service-impl 模块目录如下所示:
现在打开 父pom 文件,我们看到已创建的所有Maven模块都在 中的父pom
现在确保所有五个模块都已安装创建,如下所示:
创建后所有模块,主项目目录如下所示:
步骤23: 现在,将 SampleWebJspApplication.java 文件作为Java应用程序运行。
步骤24: 打开浏览器并调用URL http: //localhost: 8080。它返回 消息和帐号为 23。