请参见官方文档Spring指南之创建多模块项目 参见项目地址


文章目录

  • 一.简介
  • 二.你将创造什么(What You Will Build)
  • 三.Create a Root Project(创建根目录)
  • 3.1 Create the Directory Structure(创建目录结构)
  • 3.2 使用idea搭建
  • 四.Create the Library Project(创建library项目)
  • 4.1 创建目录结构
  • 4.2 Setting up the Library Project(建立Library项目)
  • 4.3 Create a Service Component(创建服务组件)
  • 4.3 Testing the Service Component(测试服务组件)
  • 4.4 测试中报错问题
  • 五.Create the Application Project(创建应用程序项目)
  • 5.1 Setting up the Application Project(设置应用程序项目)
  • 5.2 Write the Application(编写应用程序)
  • 5.3 @SpringBootApplication注解讲解
  • 5.4 测试报错问题及解决方法


一.简介

本指南向您展示了如何使用Spring Boot创建多模块项目(a multi-module project)。该项目将有一个 library jar和一个使用 library 的主应用程序(main application)。您还可以使用它来了解如何独立构建一个 library(一个不是应用程序的jar文件)。

二.你将创造什么(What You Will Build)

您将设置一个 library jar,它为简单的“Hello, World”消息公开一个服务,然后将该服务包含在一个将 library 用作依赖项的web应用程序中。You will set up a library jar that exposes a service for simple “Hello, World” messages and then include the service in a web application that uses the library as a dependency.

三.Create a Root Project(创建根目录)

本指南将介绍如何构建两个项目,其中一个是对另一个的依赖。因此,您需要在根项目下创建两个子项目。但是首先在顶层创建构建配置(But first, create the build configuration at the top level)。对于Maven,你会想要一个带有 modules 标签的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mashirro</groupId>
    <artifactId>gs-multi-module</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>pom</packaging>
    <modules>
        <module>library</module>
        <module>application</module>
    </modules>
</project>
3.1 Create the Directory Structure(创建目录结构)

在你想要作为根目录的目录下,创建以下子目录结构。在项目的根目录中,您将需要设置一个构建系统(you will need to set up a build system),本指南将向您展示如何使用Maven。

└── library
└── application
3.2 使用idea搭建

1.File-new-project-选择maven-next-输入groupid和artifactid-next-finish

四.Create the Library Project(创建library项目)

两个项目中的一个作为另一个项目(应用程序)将使用的库(One of the two projects serves as a library that the other project (the application) will use)。

4.1 创建目录结构

1.现在您需要配置一个构建工具(比如 Maven)。请注意,在 library 项目中根本没有使用Spring Boot Maven插件。这个插件的主要功能是创建一个可执行文件“über-jar”,我们既不需要也不想要它作为一个库(which we neither need nor want for a library)。虽然没有使用Spring Boot Maven插件,但你确实想利用Spring Boot依赖项管理的优势,因此可以使用Spring Boot的spring-boot-starter-parent作为父项目来配置它。另一种方法是在 pom.xml 文件的dependencyManagement 部分将依赖项管理作为物料清单(BOM)导入。

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.4</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.6.4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
4.2 Setting up the Library Project(建立Library项目)

对于Library项目,您不需要添加依赖项。基本的spring-boot-starter依赖项提供了所需的一切。

1.父项目gsmultimodule右键-new-module-选择Spring Initializr-next-填写group和artifact-next-不选择依赖-next-finish。

idea重新创建项目索引_idea重新创建项目索引

<?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.6.4</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.mashirro</groupId>
	<artifactId>library</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>library</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<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>

2.调整 Library 项目

(1)如果您从start.spring.io生成了Library项目,它将包含一个用于构建系统的包装器脚本(mvnw或gradlew,取决于您的选择)。你可以把这个脚本和它的相关配置移动到根目录:

$ mv mvnw* .mvn ..
$ mv gradlew* gradle ..

(2)Library项目没有带有 main 方法的类(因为它不是一个应用程序)。因此,您必须告诉构建系统不要尝试为Library项目构建一个可执行jar。(默认情况下,Spring Initializr构建可执行项目)。要告诉Maven不要为Library项目构建一个可执行jar文件,你必须从Spring Initializr创建的pom.xml文件中删除以下代码块:

<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
4.3 Create a Service Component(创建服务组件)

library 将提供一个MyService类,供应用程序使用。

@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类。

@ConfigurationProperties("service")
public class ServiceProperties {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
4.3 Testing the Service Component(测试服务组件)

1.您可能需要为 library 组件编写单元测试。如果您提供可重用的Spring配置作为 library 的一部分,您可能还想编写一个集成测试,以确保配置工作。为此,您可以使用JUnit和@SpringBootTest注释。

@SpringBootTest("service.message=Hello")
class LibraryApplicationTests {
	@Autowired
	private MyService myService;
	@Test
	void contextLoads() {
		System.out.println(myService.message());
	}
}

2.使用@SpringBootTest注释的默认属性为测试配置 service.message 。我们不建议将 application.properties 放入 library,因为在运行时可能会与使用 library 的应用程序发生冲突(从类路径仅加载一个application.properties)。你可以把 application.properties 放在测试类路径中,但不将其包含在jar中(例如,将其放在src/test/resources中)。

idea重新创建项目索引_spring_02

4.4 测试中报错问题

1.比如我把 library 的启动类LibraryApplication删除。然后再运行单元测试。会报以下错误:

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, 
you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test

2.两种解决方法:(1)是保留启动类(2)是在单元测试中添加以下代码:

//注解+static
	@SpringBootApplication
	static class TestConfiguration {
	}

五.Create the Application Project(创建应用程序项目)

应用程序项目使用Library项目,Library项目提供了其他项目可以使用的服务。

5.1 Setting up the Application Project(设置应用程序项目)

1.对于Application项目,您需要Spring Web和Spring Boot Actuator依赖项。

<?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.6.4</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.mashirro</groupId>
	<artifactId>application</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>application</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<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>

2.Adding the Library Dependency(添加Library依赖)

<dependency>
			<groupId>com.mashirro</groupId>
			<artifactId>library</artifactId>
			<version>${project.version}</version>
		</dependency>
5.2 Write the Application(编写应用程序)

1.编写 MyController

@RestController
public class MyController {
    private final MyService myService;
    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/")
    public String home() {
        return myService.message();
    }
}

2.创建application.properties文件
您需要在application.properties中为 Library 中的服务提供一条消息。在源文件夹中,您需要创建一个名为src/main/resources/application.properties的文件。

service.message=Hello, World
5.3 @SpringBootApplication注解讲解

1.@SpringBootApplication是一个方便的注释,它添加了以下所有内容:

  • @Configuration:将类标记为应用程序上下文的bean定义源
  • @EnableAutoConfiguration:告诉Spring Boot根据类路径设置、其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,这个注释将该应用标记为一个web应用程序,并激活关键行为,比如设置一个DispatcherServlet
  • @ComponentScan:告诉Spring在xxx包中寻找其他组件、配置和服务,让它找到控制器
5.4 测试报错问题及解决方法

1.通过启动 Application 来测试端到端结果。可以在IDE中启动应用程序,也可以使用命令行。应用程序运行后,请访问浏览器中的客户端应用程序,网址为http://localhost:8080/。报错信息如下

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.mashirro.application.controller.MyController 
required a bean of type 'com.mashirro.library.service.MyService' that could not be found.

2.因为Application(com.mashirro.application包)和MyService(com.mashirro.library.service包)是在不同的包中,所以@SpringBootApplication不能自动检测到它。有几种不同的方法可以让“MyService”被选中:

  • 直接用@Import(MyService.class)导入它。
  • 使用@SpringBootApplication(scanBasePackageClasses={…})从它的包中获取所有内容。
  • 通过名称指定父包:com.mashirro。(本指南使用此方法)
@SpringBootApplication(scanBasePackages = "com.mashirro")
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

3.其实还有一种方法:那就是直接把application项目的启动类挪到父包:com.mashirro下即可!!