本指南向您展示了如何使用Spring引导创建多模块项目,包括一个库JAR和一个使用这个库的主应用程序。您可以了解如何自己构建一个库(即,一个JAR文件)。
您将设置一个简单的库jar,它为的hello world消息提供一个公开服务,然后将该服务包含在一个Web应用程序中,涉及到Maven和Gradle。
创建一个根项目
创建如下的目录结构
在您选择的项目目录中,创建以下子目录结构;例如,在*nix系统上使用mkdir library应用程序:
└── library
└── application
在项目的根目录中,您将需要建立一个构建系统,本指南将向您展示如何使用Maven或Gradle构建。
Gradle配置
我们建议使用Gradle包装。因此,可以通过从现有项目复制包装器来安装包装器,或者通过使用包装器任务执行Gradle来安装包装器(按照Gradle文档中的说明操作)。这将为您提供一个顶级目录,如下所示:
└── library
└── application
└── gradlew
└── gradlew.bat
└── gradle
└── wrapper
└── gradle-wrapper.properties
└── gradle-wrapper.jar
Windows(非Cygwin)用户执行gradlew.bat脚本来构建项目;其他环境都使用gradlew脚本。然后将settings.gradle添加到根目录以在顶层驱动生成:
settings.gradle
rootProject.name = 'gs-multi-module'
include 'library'
include 'application'
Maven配置
我们建议使用Maven包装。因此,通过从现有项目中复制包装器,或者使用io.takari:maven:wrapper目标执行maven来安装包装器(按照包装器文档中的说明操作)。这将为您提供一个顶级目录,如下所示:
└── library
└── application
└── mvnw
└── mvnw.cmd
└── .mvn
└── wrapper
└── maven-wrapper.properties
└── maven-wrapper.jar
Windows(非cygwin)用户执行mvnw.cmd脚本来构建项目;其他环境都使用mvnw脚本。然后将pom.xml添加到根目录以在顶层驱动构建:
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>
<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>
创建一个库项目
目录结构
└── src
└── main
└── java
└── hello
└── service
现在我们需要配置一个构建工具(Maven或Gradle)。在这两种情况下,请注意Springboot插件根本没有在库项目中使用。插件的主要功能是创建一个可执行的jar,这个库中不需要。为了快速启动,以下是完整的配置:
Gradles配置
library/build.gradle
buildscript {
repositories { mavenCentral() }
}
plugins { id "io.spring.dependency-management" version "1.0.5.RELEASE" }
ext { springBootVersion = '2.1.6.RELEASE' }
apply plugin: 'java'
apply plugin: 'eclipse'
jar {
baseName = 'gs-multi-module-library'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
}
虽然没有使用SpringBoot Gradle插件,但您确实希望利用SpringBoot依赖性管理,以便使用dependency-management插件和SpringBoot中的mavenBom进行配置。
Maven配置
library/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>
<groupId>com.example</groupId>
<artifactId>gs-multi-module-library</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
虽然没有使用Spring Boot Maven插件,但您确实希望利用Spring Boot依赖性管理功能。另一种选择是在POM的<dependencyManagement/>
部分将依赖关系管理作为BOM导入。
创建服务组件
这库将提供一个myservice类,该类可供其它应用程序使用:
library/src/main/java/hello/service/MyService.java
package hello.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();
}
}
要使其在标准的Springboot中可配置,还可以添加@ConfigurationProperties类:
library/src/main/java/hello/service/ServiceProperties.java
package hello.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 boot相关的,在这种情况下,使用库的应用程序需要提供配置本身。
测试这个服务组件
您将要为这个库组件编写单元测试。如果您将可重用的Spring配置作为库的一部分提供,那么您可能还需要编写一个集成测试,以确保配置正常工作。为此,可以使用JUnit 和@SpringBootTest 注释。例如:
library/src/test/java/hello/service/MyServiceTest.java
package hello.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 {
}
}
在上面的示例中,我们使用@SpringBootTest注释的默认属性为测试配置了service.message。不建议将application.properties放入库中,因为使用它的应用程序在运行时可能会发生冲突(从类路径只加载一个application.properties)。您可以将application.properties放在测试类路径中,但不能将其包含在jar中,例如将其放在src/test/resources中。
创建Application类
目录结构如下
└── src
└── main
└── java
└── hello
└── app
不要使用与库中的包相同的包,除非您希望通过@ComponentScan在应用程序中默认包含库中的所有Spring组件。现在生成配置出现了:
Application的Maven配置
application/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>
<groupId>com.example</groupId>
<artifactId>gs-multi-module-application</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>gs-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>
Spring Boot将会你做如下的事:
- 将 classpath 里面所有用到的jar包构建成一个可执行的 JAR 文件,方便执行你的程序
- 搜索public static void main()方法并且将它当作可执行类
- 根据springboot版本,去查找相应的依赖类版本,当然你可以定义其它版本。
Application代码
application/src/main/java/hello/app/DemoApplication.java
package hello.app;
import hello.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 = "hello")
@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);
}
}
因为DemoApplication与MyService(hello.service)位于不同的包(hello.app)中,@SpringBootApplication最初不会检测到它。有不同的方法可以选择MyService:
- 通过
@Import(MyService.class)
直接引入 - 使用
@SpringBootApplication(scanBasePackageClasses={…})
扫描
本例按名称指定父包hello,来扫描
如果您的应用程序也使用JPA或Spring Data,请注意,在未明确指定时,@EntityScan和@EnableJpaRepositories注释仅从SpringBootApplication 继承其基包。也就是说,一旦指定了scanBasePackageClasses 或 scanBasePackages,可能还需要显式地提供@EntityScan和@EnableJpaRepositories ,并对它们的包扫描进行显式配置。
配置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
祝贺你!您刚刚使用了Springboot来创建一个可重用的库,然后使用它来构建一个应用程序。