本指南向您展示如何使用Spring Boot创建一个多模块项目。该项目将有一个库jar和使用该库的主应用程序。您也可以使用它来查看如何自行构建库(即不是应用程序的jar文件)。

你会建立什么

您将设置一个库jar,它公开简单的“ Hello,World”消息服务,然后将该服务包含在使用库作为依赖项的Web应用程序中。

你需要什么

如何完成本指南

像大多数Spring 入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都可以使用工作代码。

从头开始 ,继续创建根项目

跳过基础知识 ,请执行以下操作:

完成后 ,您可以根据中的代码检查结果draft-gs-multi-module/complete

首先,您设置一个基本的构建脚本。在使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含使用GradleMaven所需的代码。如果您都不熟悉,请参阅使用Gradle 构建Java项目使用Maven构建Java项目

创建一个根项目

本指南逐步完成了两个项目的构建,其中一个是对另一个项目的依赖。因此,您需要在根项目下创建两个子项目。

创建目录结构

在要用作根目录的目录中,创建以下子目录结构(例如,使用mkdir library application在* nix系统上):

└── library
└── application

在项目的根目录中,您将需要设置一个构建系统,本指南将向您展示如何使用Maven或Gradle。

[[initial] ==从Spring Initializr开始

对于所有Spring应用程序,您应该从Spring Initializr开始。Initializr提供了一种快速的方法来提取应用程序所需的所有依赖关系,并为您完成了许多设置。对于本指南,您需要运行两次Spring Initializr,一次针对库,一次针对应用程序。以下主题描述了如何对本指南中的两个项目使用Spring Initializr:

创建图书馆项目

这两个项目之一用作另一个项目(应用程序)将使用的库。

创建目录结构

在一个library目录中,创建以下子目录结构(例如,通过使用mkdir -p src/main/java/com/example/multimodule/service在* nix系统上):

└── src
    └── main
        └── java
            └── com
                └── example
                    └── multimodule
                        └── service

现在,您需要配置一个构建工具(Maven或Gradle)。在这两种情况下,请注意,库项目中根本没有使用Spring Boot插件。该插件的主要功能是创建一个可执行文件“über-jar”,而我们既不需要库又不需要库。

尽管未使用Spring Boot Maven插件,但是您确实想利用Spring Boot依赖项管理,因此可以通过使用spring-boot-starter-parent从Spring Boot作为父项目。一种替代方法是将依赖项管理作为物料清单(BOM)导入到的部分pom.xml文件。

设置图书馆项目

对于Library项目,您无需添加依赖项。基础的spring-boot-starter依赖关系提供了您所需的一切。下图显示了为Library项目设置的Initializr:

Initializr库
上图显示了选择Maven作为构建工具的Initializr。您也可以使用Gradle。它还显示了com.examplemulti-module-library分别是Group和Artifact。在本示例的其余部分中,将使用这些值。

以下清单显示了pom.xml选择Maven时创建的文件:

<?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.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>multi-module-library</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>multi-module-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>

</project>

以下清单显示了build.gradle选择Gradle时创建的文件:

plugins {
	id 'org.springframework.boot' version '2.1.8.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

调整图书馆项目

Library项目没有使用main方法的类(因为它不是应用程序)。因此,您必须告诉构建系统不要尝试为Library项目构建可执行的jar。(默认情况下,Spring Initializr会生成可执行项目。)

要告诉Maven不为Library项目构建可执行的jar,必须从pom.xml由Spring Initializr创建:

<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>2.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>multi-module-library</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>multi-module-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>

</project>

要告诉Gradle不为Library项目构建可执行的jar,必须将以下代码块添加到build.gradle由Spring Initializr创建:

bootJar {
	enabled = false
}

jar {
	enabled = true
}

bootJar任务尝试创建一个可执行jar,这需要一个main()方法。因此,您需要禁用bootJar任务并启用jar任务(创建普通的jar而不是可执行的jar)。

以下清单显示了最终的build.gradle库项目的文件:

plugins {
	id 'org.springframework.boot' version '2.1.8.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

bootJar {
	enabled = false
}

jar {
	enabled = true
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

创建服务组件

图书馆将提供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.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest("service.message=Hello")
public class MyServiceTest {

    @Autowired
    private MyService myService;

    @Test
    public void contextLoads() {
        assertThat(myService.message()).isNotNull();
    }

    @SpringBootApplication
    static class TestConfiguration {
    }

}
在前面的清单中,我们已经配置了service.message使用的默认属性进行测试@SpringBootTest注解。我们建议放置application.properties在库中,因为在运行时与使用该库的应用程序可能会发生冲突(只有一个application.properties从classpath加载)。你可以application.properties在测试类路径中,但不将其包含在jar中(例如,通过将其放入src/test/resources )。

创建应用程序项目

Application项目使用Library项目,该项目提供了其他项目可以使用的服务。

创建目录结构

在里面application目录中,创建以下子目录结构(例如, mkdir -p src/main/java/com/example/multimodule/application在* nix系统上):

└── src
    └── main
        └── java
            └── com
                └── example
                    └── multimodule
                        └── application

除非要通过以下方式在库中包含所有Spring组件,否则请不要使用与库相同的包(或库包的父包)。 @ComponentScan在应用程序中。

设置应用项目

对于Application项目,您需要Spring Web和Spring Boot Actuator依赖项。下图显示了为Application项目设置的Initializr:

初始化应用
上图显示了选择Maven作为构建工具的Initializr。您也可以使用Gradle。它还显示了com.examplemulti-module-application分别是Group和Artifact。在本示例的其余部分中,将使用这些值。

以下清单显示了pom.xml选择Maven时创建的文件:

<?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.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>multi-module-application</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>multi-module-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>

以下清单显示了build.gradle选择Gradle时创建的文件:

plugins {
	id 'org.springframework.boot' version '2.1.8.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

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'
}

添加库依赖

Application项目需要依赖Library项目。您需要相应地修改您的应用程序构建文件。

对于Maven,添加以下依赖项:

<dependency>
  <groupId>com.example</groupId>
  <artifactId>gs-multi-module-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>2.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>multi-module-application</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>multi-module-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>com.example</groupId>
			<artifactId>multi-module-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,添加以下依赖项:

compile project(':library')

以下清单显示了成品build.gradle文件:

plugins {
	id 'org.springframework.boot' version '2.1.8.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

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在不同的包装内( com.example.multimodule.application )比MyServicecom.example.multimodule.service ), @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中启动应用程序,也可以使用命令行。应用程序运行后,在浏览器中访问客户端应用程序,网址为http://localhost:8080/ 。在那里,你应该看到Hello, World反映在回应中。

如果您使用Gradle,则以下命令(实际上是依次执行两个命令)将首先构建库,然后运行应用程序:

$ ./gradlew build && ./gradlew :application:bootRun

如果使用Maven,则以下命令(实际上是依次执行两个命令)将首先构建库,然后运行应用程序:

$ ./mvnw install && ./mvnw spring-boot:run -pl application

摘要

恭喜你!您已经使用Spring Boot创建了可重用的库,然后使用该库来构建应用程序。

也可以看看

以下指南也可能会有所帮助:

是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则

所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创作共用许可证发布