开发时服务
开发时服务提供运行应用所需的外部依赖。 它们只在开发过程中使用,应用部署时会被禁用。
Spring Boot 支持两个开发阶段服务:Docker Compose 和 Testcontainers。 接下来的章节将提供更多细节。
Docker 组合支持
Docker Compose 是一种流行的技术,可以用来定义和管理多个容器,满足你的应用需求。
一个compose.yml文件通常会在你的应用程序旁边创建,用于定义和配置服务容器。
Docker Compose 的典型工作流程是运行Docker Compose Up,先把应用连接到启动服务,然后运行Docker Compose down等你完成后。
这Spring-boot-docker-compose模块可以包含在项目中,以支持使用 Docker Compose 处理容器。
在你的构建中添加模块依赖,如下 Maven 和 Gradle 的列表所示:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
dependencies {
developmentOnly("org.springframework.boot:spring-boot-docker-compose")
}
当该模块作为依赖包含时,Spring Boot 将执行以下作:
-
搜索
compose.yml以及工作目录中其他常见的 compose 文件名 -
叫
Docker Compose Up与发现者compose.yml -
为每个支持的容器创建服务连接豆
-
叫
Docker Compose 停止当应用程序被关闭时
如果启动应用时 Docker Compose 服务已经在运行,Spring Boot 只会为每个支持的容器创建服务连接豆。
它不会叫Docker Compose Up又来了,它不叫Docker Compose 停止当应用程序被关闭时。
重新打包的归档默认不包含 Spring Boot 的 Docker Compose。
如果你想使用这些支持,就必须包含它。
使用 Maven 插件时,设置exclusionDockerCompose属性到false.
使用Gradle插件时,配置任务的类路径以包含仅开发配置. |
服务连接
服务连接是指连接到任何远程服务的连接。 Spring Boot 的自动配置可以消耗服务连接的详细信息,并利用这些细节建立与远程服务的连接。 在此过程中,连接细节优先于任何与连接相关的配置属性。
使用 Spring Boot 的 Docker Compose 支持时,服务连接会建立到容器映射的端口。
| Docker 组合通常以一种方式使用,使容器内的端口映射到你电脑上的临时端口。 例如,一台 Postgres 服务器可能在容器内运行,使用端口 5432,但本地映射到完全不同的端口。 服务连接始终会发现并使用本地映射的端口。 |
服务连接通过使用容器的映像名称来建立。 目前支持的服务连接如下:
| 连接详情 | 匹配内容 |
|---|---|
名为“symptoma/activemq”或“apache/activemq-classic”的容器 |
|
名为“apache/activemq-artemis”的容器 |
|
名为“卡桑德拉”的容器 |
|
名为“elasticsearch”的容器 |
|
名为“hazelcast/hazelcast”的容器。 |
|
名为“clickhouse/clickhouse-server”、“gvenzl/oracle-free”、“gvenzl/oracle-xe”、“mariadb”、“mssql/server”、“mysql” 或 “postgres”的容器 |
|
名为“osixia/openldap”、“lldap/lldap”的容器 |
|
名为“mongo”的集装箱 |
|
名为“neo4j”的容器 |
|
名为“otel/opentelemetry-collector-contrib”、“grafana/otel-lgtm”的容器 |
|
名为“otel/opentelemetry-collector-contrib”、“grafana/otel-lgtm”的容器 |
|
名为“otel/opentelemetry-collector-contrib”、“grafana/otel-lgtm”的容器 |
|
名为“apachepulsar/pulsar”的容器 |
|
名为“clickhouse/clickhouse-server”、“gvenzl/oracle-free”、“gvenzl/oracle-xe”、“mariadb”、“mssql/server”、“mysql” 或 “postgres”的容器 |
|
名为“rabbitmq”的容器 |
|
名为“redis”、“redis/redis-stack”或“redis/redis-stack-server”的容器 |
|
这些集装箱名为“openzipkin/zipkin”。 |
SSL 支持
有些镜像开箱即用 SSL,或者你想让容器开启 SSL 来镜像你的生产环境。 Spring Boot 支持支持的服务连接的 SSL 配置。 请注意,你仍然需要在容器内运行的服务上启用SSL,这个功能只在你的应用客户端配置SSL。
以下服务连接支持SSL:
-
Cassandra
-
沙发底座
-
弹性搜索
-
卡 夫 卡
-
MongoDB
-
兔子MQ
-
Redis
要启用服务的 SSL 支持,可以使用服务标签。
对于基于JKS的密钥存储器和信任存储,您可以使用以下容器标签:
-
org.springframework.boot.sslbundle.jks.key.别名 -
org.springframework.boot.sslbundle.jks.key.password(.password) -
org.springframework.boot.sslbundle.jks.options.ciphers -
org.springframework.boot.sslbundle.jks.options.enabled-protocols -
org.springframework.boot.sslbundle.jks.protocol -
org.springframework.boot.sslbundle.jks.keystore.type -
org.springframework.boot.sslbundle.jks.keystore.provider(org.springframework.boot.sl.bundle.jks.keystore.provider) -
org.springframework.boot.sslbundle.jks.keystore.location -
org.springframework.boot.sslbundle.jks.keystore.password -
org.springframework.boot.sslbundle.jks.truststore.type -
org.springframework.boot.sslbundle.jks.truststore.provider -
org.springframework.boot.sslbundle.jks.truststore.location -
org.springframework.boot.sslbundle.jks.truststore.password
这些标签与SSL捆绑包的特性相符。
对于基于PEM的密钥存储和信任存储,可以使用以下容器标签:
-
org.springframework.boot.sslbundle.pem.key.别名 -
org.springframework.boot.sslbundle.pem.key.password -
org.springframework.boot.sslbundle.pem.options.ciphers -
org.springframework.boot.sslbundle.pem.options.enabled-protocols -
org.springframework.boot.sslbundle.pem.protocol -
org.springframework.boot.sslbundle.pem.keystore.type -
org.springframework.boot.sslbundle.pem.keystore.certificate -
org.springframework.boot.sslbundle.pem.keystore.private-key -
org.springframework.boot.sslbundle.pem.keystore.private-key-password -
org.springframework.boot.sslbundle.pem.truststore.type -
org.springframework.boot.sslbundle.pem.truststore.certificate -
org.springframework.boot.sslbundle.pem.truststore.private-key -
org.springframework.boot.sslbundle.pem.truststore.private-key-password
这些标签与SSL捆绑包的特性相符。
以下示例为 Redis 容器启用了 SSL:
services:
redis:
image: 'redis:latest'
ports:
- '6379'
secrets:
- ssl-ca
- ssl-key
- ssl-cert
command: 'redis-server --tls-port 6379 --port 0 --tls-cert-file /run/secrets/ssl-cert --tls-key-file /run/secrets/ssl-key --tls-ca-cert-file /run/secrets/ssl-ca'
labels:
- 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'
- 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'
- 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'
secrets:
ssl-ca:
file: 'ca.crt'
ssl-key:
file: 'server.key'
ssl-cert:
file: 'server.crt'
自定义图片
有时你可能需要使用自己版本的图片来提供服务。 你可以使用任何自定义图片,只要它的行为和标准图片一样。 具体来说,标准镜像支持的任何环境变量也必须在你的自定义镜像中使用。
如果你的图片用了不同的名字,你可以在你的compose.yml文件,使 Spring Boot 能够提供服务连接。
使用名为org.springframework.boot.service-connection提供服务名称。
例如:
services:
redis:
image: 'mycompany/mycustomredis:7.0'
ports:
- '6379'
labels:
org.springframework.boot.service-connection: redis
跳过特定容器
如果你在你的compose.yml如果你不想和你的应用关联,可以用标签来忽略它。
任何标有org.springframework.boot.ignore春季新兵会忽略。
例如:
services:
redis:
image: 'redis:7.0'
ports:
- '6379'
labels:
org.springframework.boot.ignore: true
使用特定的 compose 文件
如果你的 compose 文件不和你的应用在同一个目录里,或者它的名称不同,你可以用spring.docker.compose.file在你的application.properties或application.yaml指向另一个文件。
属性可以定义为精确路径或相对于你的应用的路径。
例如:
-
Properties
-
YAML
spring.docker.compose.file=../my-compose.yml
spring:
docker:
compose:
file: "../my-compose.yml"
等待集装箱准备
由 Docker Compose 启动的容器可能需要一些时间才能完全准备好。
推荐的检查准备情况的方法是添加一个健康检查服务定义下的部分,在你的compose.yml文件。
因为这种情况并不罕见健康检查配置应省略于compose.ymlSpring Boot 也会直接检查服务准备情况。
默认情况下,当能够建立到映射端口的TCP/IP连接时,容器被视为准备就绪。
你可以在每个容器上添加一个org.springframework.boot.readiness-check.tcp.disable在你的标签中compose.yml文件。
例如:
services:
redis:
image: 'redis:7.0'
ports:
- '6379'
labels:
org.springframework.boot.readiness-check.tcp.disable: true
你也可以在你的超时值里更改application.properties或application.yaml文件:
-
Properties
-
YAML
spring.docker.compose.readiness.tcp.connect-timeout=10s
spring.docker.compose.readiness.tcp.read-timeout=5s
spring:
docker:
compose:
readiness:
tcp:
connect-timeout: 10s
read-timeout: 5s
整体超时可以通过以下方式配置spring.docker.compose.readiness.timeout.
控制 Docker 组合生命周期
默认情况下,Spring Boot调用Docker Compose Up当你的申请开始时Docker Compose 停止当它关闭时。
如果你更喜欢不同的生命周期管理,可以使用spring.docker.compose.lifecycle-management财产。
支持以下数值:
-
没有- 不要启动或停止Docker Compose -
仅限起始- 应用启动时启动Docker Compose并保持运行 -
开始与停止- 应用程序启动时启动 Docker Compose,JVM 退出时停止
此外,你还可以使用spring.docker.compose.start.command性质 以改变Docker Compose Up或Docker Compose Start被使用。
这spring.docker.compose.stop.command允许你配置Docker Compose down或Docker Compose 停止被使用。
以下示例展示了生命周期管理的配置方式:
-
Properties
-
YAML
spring.docker.compose.lifecycle-management=start-and-stop
spring.docker.compose.start.command=start
spring.docker.compose.stop.command=down
spring.docker.compose.stop.timeout=1m
spring:
docker:
compose:
lifecycle-management: start-and-stop
start:
command: start
stop:
command: down
timeout: 1m
激活Docker Compose配置文件
Docker Compose配置文件类似于Spring配置文件,允许你根据特定环境调整Docker Compose配置。
如果你想激活特定的 Docker Compose 配置文件,可以使用spring.docker.compose.profiles.active财产在你的application.properties或application.yaml文件:
-
Properties
-
YAML
spring.docker.compose.profiles.active=myprofile
spring:
docker:
compose:
profiles:
active: "myprofile"
测试容器支持
除了用Testcontainer进行集成测试外,也可以在开发阶段使用。 接下来的章节将提供更多细节。
开发时使用 Testcontainer
这种方法允许开发者快速启动应用依赖的服务容器,免去了手动配置数据库服务器等资源的需求。 以这种方式使用测试容器提供了类似于 Docker Compose 的功能,只是你的容器配置是用 Java 而非 YAML 进行的。
在开发阶段使用Testcontainers,你需要使用“test”类路径启动应用,而不是“main”类路径。 这样你就能访问所有声明的测试依赖,并为你提供一个自然的配置配置。
要创建可测试启动的应用程序版本,你应该在SRC/测试目录。
例如,如果你的主要应用是src/main/java/com/example/MyApplication.java你应该创造src/test/java/com/example/TestMyApplication.java
这TestMyApplication类可以使用SpringApplication.from(...)启动真实应用的方法:
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main).run(args);
}
}
import org.springframework.boot.fromApplication
fun main(args: Array<String>) {
fromApplication<MyApplication>().run(*args)
}
你还需要定义容器你想在申请时开始的实例。
为此,你需要确保Spring Boot测试容器模块已被添加为测试Dependency。
完成后,你可以创建一个@TestConfiguration宣告@Bean你想开始的容器的方法。
你也可以对你的@Bean方法:@ServiceConnection为了创造连接详情豆。
有关支持技术的详细信息,请参见服务连接部分。
典型的Testcontainer配置如下:
-
Java
-
Kotlin
import org.testcontainers.neo4j.Neo4jContainer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
@ServiceConnection
public Neo4jContainer neo4jContainer() {
return new Neo4jContainer("neo4j:5");
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.neo4j.Neo4jContainer
@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {
@Bean
@ServiceConnection
fun neo4jContainer(): Neo4jContainer {
return Neo4jContainer("neo4j:5")
}
}
的生命周期容器豆子由 Spring Boot 自动管理。
集装箱会自动启动和停止。 |
你可以使用Spring.testcontainers.beans.startup属性 以改变容器的初始化方式。
默认情况下顺序虽然使用启动,但你也可以选择平行如果你想同时启动多个容器。 |
一旦你定义了测试配置,就可以使用与(...)将它连接到测试发射器的方法:
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main).with(MyContainersConfiguration.class).run(args);
}
}
import org.springframework.boot.fromApplication
import org.springframework.boot.with
fun main(args: Array<String>) {
fromApplication<MyApplication>().with(MyContainersConfiguration::class).run(*args)
}
你现在可以发射了TestMyApplication就像你对待普通 Java 一样主要方法应用来启动你的应用程序及其需要运行的容器。
你可以用Maven的目标Spring Boot:测试运行或Gradle任务bootTestRun从命令行作。 |
在开发阶段贡献动态属性
如果你想在开发阶段贡献动态属性,从你的容器 @Bean方法,定义一个额外的DynamicPropertyRegistrar豆。
注册商应使用以下方式定义@Bean将属性来源容器作为参数注入的方法。
这种安排确保在使用这些物业之前,集装箱已经启动。
典型的配置如下:
-
Java
-
Kotlin
import org.testcontainers.mongodb.MongoDBContainer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistrar;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
public MongoDBContainer mongoDbContainer() {
return new MongoDBContainer("mongo:5.0");
}
@Bean
public DynamicPropertyRegistrar mongoDbProperties(MongoDBContainer container) {
return (properties) -> {
properties.add("spring.mongodb.host", container::getHost);
properties.add("spring.mongodb.port", container::getFirstMappedPort);
};
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.test.context.DynamicPropertyRegistrar;
import org.testcontainers.mongodb.MongoDBContainer
@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {
@Bean
fun mongoDbContainer(): MongoDBContainer {
return MongoDBContainer("mongo:5.0")
}
@Bean
fun mongoDbProperties(container: MongoDBContainer): DynamicPropertyRegistrar {
return DynamicPropertyRegistrar { properties ->
properties.add("spring.mongodb.host") { container.host }
properties.add("spring.mongodb.port") { container.firstMappedPort }
}
}
}
使用@ServiceConnection尽可能推荐使用动态特性,但对于尚未具备的技术来说,动态属性可以作为有用的备选方案@ServiceConnection支持。 |
导入Testcontainers 声明 Classes
使用测试容器时的一个常见模式是声明容器实例以静态字段形式存在。
这些字段通常直接定义在测试类上。
它们也可以在父类或测试实现的接口上声明。
例如,如下我的容器接口声明蒙哥和neo4j器皿:
-
Java
-
Kotlin
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.mongodb.MongoDBContainer;
import org.testcontainers.neo4j.Neo4jContainer;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
public interface MyContainers {
@Container
@ServiceConnection
MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");
@Container
@ServiceConnection
Neo4jContainer neo4jContainer = new Neo4jContainer("neo4j:5");
}
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.mongodb.MongoDBContainer
import org.testcontainers.neo4j.Neo4jContainer
interface MyContainers {
companion object {
@Container
@ServiceConnection
@JvmField
val mongoContainer = MongoDBContainer("mongo:5.0")
@Container
@ServiceConnection
@JvmField
val neo4jContainer = Neo4jContainer("neo4j:5")
}
}
如果你已经有这样定义的容器,或者你更喜欢这种风格,你可以导入这些声明类,而不是定义容器@Bean方法。
为此,添加@ImportTestcontainers对你的测试配置类的注释:
-
Java
-
Kotlin
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.context.ImportTestcontainers;
@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers.class)
public class MyContainersConfiguration {
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.context.ImportTestcontainers
@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers::class)
class MyContainersConfiguration
如果你不打算使用服务连接功能,但想使用@DynamicPropertySource相反,移除@ServiceConnection注释来自容器领域。
你也可以添加@DynamicPropertySource为你的声明类添加注释方法。 |
在开发阶段使用 DevTools 与 Testcontainer 的应用
使用开发工具时,你可以用@RestartScope.
当开发工具重启应用时,这些豆子不会被重新生成。
这对容器豆子,因为即使重新开始应用,它们依然保持状态。
-
Java
-
Kotlin
import org.testcontainers.mongodb.MongoDBContainer;
import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
@RestartScope
@ServiceConnection
public MongoDBContainer mongoDbContainer() {
return new MongoDBContainer("mongo:5.0");
}
}
import org.springframework.boot.devtools.restart.RestartScope
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.mongodb.MongoDBContainer
@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {
@Bean
@RestartScope
@ServiceConnection
fun mongoDbContainer(): MongoDBContainer {
return MongoDBContainer("mongo:5.0")
}
}
如果你正在使用 Gradle 并想使用这个功能,你需要更改Spring-boot-devtools依赖关系仅开发自测试与开发仅限.
默认范围为仅开发这bootTestRun任务不会检测代码中的更改,因为开发工具未激活。 |