对于最新的稳定版本,请使用 spring-cloud-contract 4.3.0spring-doc.cadn.net.cn

如何将通用存储库与合约一起使用,而不是将它们存储在生产者那里?

存储合同的另一种方式,而不是将它们交给生产者,是保留 它们在一个共同的地方。这种情况可能与安全问题有关(其中 消费者无法克隆生产者的代码)。另外,如果您将合同保存在一个地方, 然后,作为生产者,你知道你有多少消费者,你可能会破坏哪个消费者 与您本地的更改。spring-doc.cadn.net.cn

回购结构

假设我们有一个坐标为com.example:server和三个 消费者:client1,client2client3.然后,在存储库中,使用 common contracts,您可以进行以下设置(您可以在 Spring Cloud Contract 的存储库中查看 samples/standalone/contracts子文件夹)。 以下列表显示了这样的结构:spring-doc.cadn.net.cn

├── com
│   └── example
│       └── server
│           ├── client1
│           │   └── expectation.groovy
│           ├── client2
│           │   └── expectation.groovy
│           ├── client3
│           │   └── expectation.groovy
│           └── pom.xml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    └── assembly
        └── contracts.xml

在斜杠分隔下groupid/artifact id文件夹 (com/example/server),你有 三大消费者的期望(client1,client2client3).期望是标准的 Groovy DSL contract 文件,如本文档中所述。此存储库必须生成一个 JAR 文件,该文件映射 一对一访问存储库的内容。spring-doc.cadn.net.cn

以下示例显示了pom.xml文件server文件夹:spring-doc.cadn.net.cn

除了 Spring Cloud Contract Maven 插件之外,没有其他依赖项。 那些pom.xml文件是消费者端运行所必需的mvn clean install -DskipTests在本地安装 生产者项目的存根。spring-doc.cadn.net.cn

pom.xml根文件夹中的文件可能如下所示:spring-doc.cadn.net.cn

它使用汇编插件来构建包含所有合约的 JAR。以下示例 显示这样的设置:spring-doc.cadn.net.cn

工作流程

该工作流假定 Spring Cloud Contract 是在消费者和 制片人方面。在公共存储库中也有适当的插件设置,其中 合同。CI 作业设置为公共存储库,以构建所有 合同并将其上传到 Nexus 或 Artifactory。下图显示了此 UML 工作流程:spring-doc.cadn.net.cn

如何通用存储库

消费者

当消费者想要离线处理合约而不是克隆生产者时 代码,消费者团队克隆公共存储库,转到所需生产者的 文件夹(例如,com/example/server) 并运行mvn clean install -DskipTests自 在本地安装从合约转换的存根。spring-doc.cadn.net.cn

您需要在本地安装 Maven

制作人

作为生产者,您可以更改 Spring Cloud Contract Verifier 以提供 URL 和 包含合约的 JAR 的依赖关系,如下所示:spring-doc.cadn.net.cn

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<contractsMode>REMOTE</contractsMode>
		<contractsRepositoryUrl>
			https://link/to/your/nexus/or/artifactory/or/sth
		</contractsRepositoryUrl>
		<contractDependency>
			<groupId>com.example.standalone</groupId>
			<artifactId>contracts</artifactId>
		</contractDependency>
	</configuration>
</plugin>

通过此设置,具有groupidcom.example.standaloneartifactidcontracts下载自link/to/your/nexus/or/artifactory/or/sth.是的 然后在本地临时文件夹中解压,并且com/example/server被选为用于生成测试和存根的存根。由于 对于这个约定,生产者团队可以知道哪些消费者团队在什么时候被破坏了 进行了一些不兼容的更改。spring-doc.cadn.net.cn

其余的流程看起来是一样的。spring-doc.cadn.net.cn

如何定义每个主题而不是每个生产者的消息传递契约?

为了避免在公共仓库中重复消息传递契约,当几个生产者将消息写入一个主题时, 我们可以创建一个结构,其中 REST 契约被放置在每个生产者和消息传递的文件夹中 合同放置在每个主题的文件夹中。spring-doc.cadn.net.cn

对于 Maven 项目

为了使在生产者端工作成为可能,我们应该为通过我们感兴趣的消息传递主题过滤常见的存储库 jar 文件。 这includedFilesMaven Spring Cloud Contract 插件的属性让我们这样做。 也contractsPath需要指定,因为默认路径为公共存储库groupid/artifactid. 以下示例显示了 MavenSpring Cloud Contract 的插件:spring-doc.cadn.net.cn

<plugin>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-contract-maven-plugin</artifactId>
   <version>${spring-cloud-contract.version}</version>
   <configuration>
      <contractsMode>REMOTE</contractsMode>
      <contractsRepositoryUrl>https://link/to/your/nexus/or/artifactory/or/sth</contractsRepositoryUrl>
      <contractDependency>
         <groupId>com.example</groupId>
         <artifactId>common-repo-with-contracts</artifactId>
         <version>+</version>
      </contractDependency>
      <contractsPath>/</contractsPath>
      <baseClassMappings>
         <baseClassMapping>
            <contractPackageRegex>.*messaging.*</contractPackageRegex>
            <baseClassFQN>com.example.services.MessagingBase</baseClassFQN>
         </baseClassMapping>
         <baseClassMapping>
            <contractPackageRegex>.*rest.*</contractPackageRegex>
            <baseClassFQN>com.example.services.TestBase</baseClassFQN>
         </baseClassMapping>
      </baseClassMappings>
      <includedFiles>
         <includedFile>**/${project.artifactId}/**</includedFile>
         <includedFile>**/${first-topic}/**</includedFile>
         <includedFile>**/${second-topic}/**</includedFile>
      </includedFiles>
   </configuration>
</plugin>
前面的 Maven 插件中的许多值都可以更改。我们将其包含在内是为了说明目的,而不是试图提供“典型”示例。

对于 Gradle 项目

要使用 Gradle 项目,请执行以下作:spring-doc.cadn.net.cn

  1. 为公共存储库依赖项添加自定义配置,如下所示:spring-doc.cadn.net.cn

    ext {
        contractsGroupId = "com.example"
        contractsArtifactId = "common-repo"
        contractsVersion = "1.2.3"
    }
    
    configurations {
        contracts {
            transitive = false
        }
    }
  2. 将公共存储库依赖项添加到类路径,如下所示:spring-doc.cadn.net.cn

    dependencies {
        contracts "${contractsGroupId}:${contractsArtifactId}:${contractsVersion}"
        testCompile "${contractsGroupId}:${contractsArtifactId}:${contractsVersion}"
    }
  3. 将依赖项下载到适当的文件夹,如下所示:spring-doc.cadn.net.cn

    task getContracts(type: Copy) {
        from configurations.contracts
        into new File(project.buildDir, "downloadedContracts")
    }
  4. 解压缩 JAR,如下所示:spring-doc.cadn.net.cn

    task unzipContracts(type: Copy) {
        def zipFile = new File(project.buildDir, "downloadedContracts/${contractsArtifactId}-${contractsVersion}.jar")
        def outputDir = file("${buildDir}/unpackedContracts")
    
        from zipTree(zipFile)
        into outputDir
    }
  5. 清理未使用的合约,如下所示:spring-doc.cadn.net.cn

    task deleteUnwantedContracts(type: Delete) {
        delete fileTree(dir: "${buildDir}/unpackedContracts",
            include: "**/*",
            excludes: [
                "**/${project.name}/**"",
                "**/${first-topic}/**",
                "**/${second-topic}/**"])
    }
  6. 创建任务依赖项,如下所示:spring-doc.cadn.net.cn

    unzipContracts.dependsOn("getContracts")
    deleteUnwantedContracts.dependsOn("unzipContracts")
    build.dependsOn("deleteUnwantedContracts")
  7. 通过指定包含合约的目录来配置插件,方法是将 这contractsDslDir属性,如下所示:spring-doc.cadn.net.cn

    contracts {
        contractsDslDir = new File("${buildDir}/unpackedContracts")
    }