Skip to content

CoApi 贡献者指南 ​

代码仓库 | 主分支

目录 ​

简介 ​

欢迎阅读 CoApi 贡献者指南!CoApi 是一个 Spring Framework 库,为 Spring 6 HTTP Interface 客户端提供零样板自动配置。本指南旨在帮助你理解代码库、有效贡献代码,并快速上手项目开发。

CoApi 通过在支持响应式和同步编程模型的同时,为 HTTP Interface 客户端提供自动配置,填补了 Spring 生态系统的空白。无论你是经验丰富的 Spring 开发者还是 HTTP 客户端的新手,本指南都将帮助你理解 CoApi 的工作原理以及如何为其持续开发做出贡献。

你将学到什么 ​

通过阅读本指南,你将了解:

  • Spring Framework 6 和 Spring Boot 4.x 的基础知识
  • CoApi 如何与 Spring 的 HTTP Interface 集成
  • CoApi 中使用的架构和设计模式
  • 如何设置开发环境
  • 测试策略和贡献工作流程
  • 负载均衡和认证等高级功能

前提条件 ​

在深入学习本指南之前,你应该具备:

  • Java/Kotlin 和 Spring Framework 的基础知识
  • 理解 HTTP 客户端和 REST API
  • 熟悉 Gradle 构建系统
  • 使用 Git 进行版本控制的经验

第一部分:语言/框架基础 ​

Spring Framework 6 和 Spring Boot 4.x ​

CoApi 基于 Spring Framework 6 和 Spring Boot 4.x 构建,因此理解这些框架的基础知识至关重要。

Spring Framework 6 主要特性 ​

Spring Framework 6 引入了几项重要的变更和改进:

  • 虚拟线程支持:Java 17+ 虚拟线程,提升并发性能
  • 性能优化:优化的 bean 创建和依赖注入
  • 类型提示:改进的类型推断和泛型支持
  • 可观测性:增强的可观测性工具集成

Spring Boot 4.x 兼容性 ​

CoApi 2.x 专为 Spring Boot 4.x 设计:

kotlin
// build.gradle.kts
dependencies {
    implementation("org.springframework.boot:spring-boot:4.0.0")
    implementation("org.springframework:spring-web:6.0.0")
}

Spring Boot 4.x 提供:

  • 自动配置:简化 Spring 应用程序的配置
  • Actuator:生产级功能
  • 嵌入式服务器:便捷的部署选项

Kotlin 语言要点 ​

CoApi 使用 Kotlin 编写,利用其现代语言特性实现更清晰、更富有表现力的代码。

使用的主要 Kotlin 特性 ​

  1. 类型安全构建器:用于配置和 bean 定义
kotlin
@BeanDefinitionBuilder.genericBeanDefinition(WebClientFactoryBean::class.java)
    .addConstructorArgValue(coApiDefinition)
  1. 扩展函数:用于工具方法
kotlin
fun String.withBearerPrefix(): String = "Bearer $this"
  1. 空安全:编译时空值检查
kotlin
val coApi = getAnnotation(CoApi::class.java)
    ?: throw IllegalArgumentException("The class must be annotated by @CoApi.")
  1. 数据类:用于不可变数据持有者
kotlin
data class CoApiDefinition(
    val name: String,
    val apiType: Class<*>,
    val baseUrl: String,
    val loadBalanced: Boolean
)

Kotlin DSL for Gradle ​

项目使用 Kotlin DSL 进行构建脚本编写:

kotlin
plugins {
    kotlin("jvm") version "1.8.0"
    id("org.springframework.boot") version "4.0.0"
}

dependencies {
    implementation("me.ahoo.coapi:coapi-spring-boot-starter:2.0.0")
}

Spring HTTP Interface ​

Spring Framework 6 引入了 HTTP Interface,允许使用 @HttpExchange 注解将 HTTP 服务定义为 Java 接口。

@HttpExchange 注解 ​

@HttpExchange 注解将接口标记为 HTTP 服务:

java
@HttpExchange("https://api.github.com")
public interface GitHubApiClient {
    
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable repo: String);
    
    @PostExchange("users/{user}/repos")
    Mono<Repository> createRepo(@PathVariable String user, @RequestBody Repository repo);
}

支持的 HTTP 方法 ​

CoApi 支持所有标准 HTTP 方法:

kotlin
@GetExchange("GET /users/{user}")
fun getUser(@PathVariable user: String): Mono<User>

@PostExchange("POST /users")
fun createUser(@RequestBody user: User): Mono<User>

@PutExchange("PUT /users/{id}")
fun updateUser(@PathVariable id: String, @RequestBody user: User): Mono<User>

@DeleteExchange("DELETE /users/{id}")
fun deleteUser(@PathVariable id: String): Mono<Void>

HTTP Interface 的优势 ​

  1. 类型安全:HTTP 方法和路径的编译时检查
  2. 响应式支持:原生支持 Project Reactor 类型
  3. 简化测试:易于模拟和测试
  4. 一致的 API:定义 HTTP 服务的标准化方式

HTTP 客户端:WebClient 与 RestClient ​

CoApi 同时支持响应式(WebClient)和同步(RestClient)HTTP 客户端,可根据应用需求灵活选择。

WebClient(响应式) ​

WebClient 是 Spring 的响应式 HTTP 客户端:

kotlin
val client = WebClient.builder()
    .baseUrl("https://api.github.com")
    .build()

client.get()
    .uri("/repos/{owner}/{repo}/issues", "Ahoo-Wang", "CoApi")
    .retrieve()
    .bodyToFlux<Issue>()
    .collectList()

特性:

  • 非阻塞式响应式
  • 支持流式响应
  • 基于 Project Reactor 构建
  • 适合高吞吐量应用

RestClient(同步) ​

RestClient 是 Spring 的现代同步 HTTP 客户端:

kotlin
val client = RestClient.builder()
    .baseUrl("https://api.github.com")
    .build()

val issues = client.get()
    .uri("/repos/{owner}/{repo}/issues", "Ahoo-Wang", "CoApi")
    .retrieve()
    .bodyToList<Issue>()

特性:

  • 简单同步
  • 标准 Java 类型
  • 易于使用和理解
  • 适合传统应用

CoApi 客户端模式配置 ​

CoApi 自动选择合适的客户端模式:

kotlin
enum class ClientMode {
    REACTIVE, SYNC, AUTO;
    
    companion object {
        fun inferClientMode(getProperty: (propertyKey: String) -> String?): ClientMode {
            val propertyValue = getProperty(COAPI_CLIENT_MODE_PROPERTY) ?: AUTO.name
            val mode = ClientMode.valueOf(propertyValue.uppercase())
            return if (mode == AUTO) {
                INFERRED_MODED_BASED_ON_CLASS
            } else {
                mode
            }
        }
    }
}

依赖注入与配置 ​

Spring 的依赖注入框架是 CoApi 功能的核心。

@Bean 定义 ​

CoApi 使用 @Bean 定义来创建代理实例:

kotlin
@Bean
fun coApiProxyFactory(): HttpServiceProxyFactory {
    return HttpServiceProxyFactory.builderFor(httpExchangeAdapter).build()
}

FactoryBean 模式 ​

CoApi 实现 FactoryBean 模式来创建代理:

kotlin
class CoApiFactoryBean(
    private val coApiDefinition: CoApiDefinition
) : FactoryBean<Any>, ApplicationContextAware {
    
    override fun getObject(): Any {
        val httpServiceProxyFactory = HttpServiceProxyFactory.builderFor(httpExchangeAdapter).build()
        return httpServiceProxyFactory.createClient(coApiDefinition.apiType)
    }
    
    override fun getObjectType(): Class<*> = coApiDefinition.apiType
}

Bean Definition Registry ​

CoApi 以编程方式注册 bean 定义:

kotlin
fun register(coApiDefinition: CoApiDefinition) {
    val beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CoApiFactoryBean::class.java)
    beanDefinitionBuilder.addConstructorArgValue(coApiDefinition)
    registry.registerBeanDefinition(coApiDefinition.coApiBeanName, beanDefinitionBuilder.beanDefinition)
}

第二部分:CoApi 架构与领域模型 ​

项目结构 ​

CoApi 采用模块化架构,职责划分清晰:

CoApi/
├── api/                    # 核心注解和接口
│   └── src/main/kotlin/me/ahoo/coapi/api/
│       ├── CoApi.kt       # 主注解
│       └── LoadBalanced.kt # 负载均衡注解
├── spring/                # 核心 Spring 集成
│   └── src/main/kotlin/me/ahoo/coapi/spring/
│       ├── EnableCoApi.kt          # 启用注解
│       ├── CoApiRegistrar.kt       # Bean 注册
│       ├── CoApiDefinition.kt      # 领域模型
│       ├── ClientMode.kt          # 客户端模式配置
│       └── client/                # HTTP 客户端实现
│           ├── reactive/           # WebClient 实现
│           └── sync/               # RestClient 实现
├── spring-boot-starter/   # Spring Boot 自动配置
│   └── src/main/kotlin/me/ahoo/coapi/spring/boot/
│       └── AutoCoApiConfiguration.kt
├── bom/                   # 物料清单
└── dependencies/          # 共享依赖管理

核心架构 ​

分层架构 ​

CoApi 采用分层架构模式:

mermaid
graph TD
    A[Application Layer] --> B[CoApi Interface Layer]
    B --> C[Spring Integration Layer]
    C --> D[HTTP Client Layer]
    D --> E[HTTP Transport Layer]
    
    A -->|CoApi| B
    B -->|EnableCoApi| C
    C -->|CoApiRegistrar| D
    D -->|WebClient/RestClient| E

组件职责 ​

  1. api 模块:包含核心注解和接口

    • @CoApi:标记接口的主注解
    • @LoadBalanced:启用客户端负载均衡
  2. spring 模块:核心 Spring 集成

    • Bean 注册和配置
    • 客户端模式检测
    • 代理创建
  3. spring-boot-starter:自动配置

    • 自动检测和设置
    • 基于属性的配置
  4. dependencies:共享依赖管理

    • 跨模块版本对齐

注册流程 ​

注册流程是 CoApi 功能的核心,将注解接口转换为代理 HTTP 客户端。

注解处理 ​

  1. @CoApi 注解:将接口标记为 HTTP 客户端
kotlin
@CoApi(baseUrl = "${github.url}")
public interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}
  1. @EnableCoApi 注解:启用自动配置
kotlin
@EnableCoApi(clients = [GitHubApiClient::class])
@SpringBootApplication
class Application

注册流程 ​

mermaid
sequenceDiagram
    autonumber
    participant App as Application
    participant Enable as EnableCoApi
    participant Registrar as EnableCoApiRegistrar
    participant Abstract as AbstractCoApiRegistrar
    participant CoApi as CoApiRegistrar
    participant Bean as BeanDefinitionRegistry
    
    App->>Enable: @EnableCoApi(clients=[GitHubApiClient])
    Enable->>Registrar: Get annotation attributes
    Registrar->>Abstract: getCoApiDefinitions()
    Abstract->>Registrar: enableCoApi attributes
    Registrar->>CoApi: register(coApiDefinitions)
    
    Note over CoApi: ClientMode.AUTO -> REACTIVE
    CoApi->>Bean: registerWebClient()
    CoApi->>Bean: registerApiClient()
    
    Note over Bean: WebClient.GitHubApi.HttpClient
    Note over Bean: GitHubApi.CoApi

Bean 注册详情 ​

注册流程创建两种类型的 bean:

  1. HTTP Client Bean:实际的 HTTP 客户端(WebClient 或 RestClient)
  2. CoApi Proxy Bean:实现该接口的代理
kotlin
// From CoApiRegistrar.kt
fun register(coApiDefinition: CoApiDefinition) {
    if (clientMode == ClientMode.SYNC) {
        registerRestClient(registry, coApiDefinition)
    } else {
        registerWebClient(registry, coApiDefinition)
    }
    registerApiClient(registry, coApiDefinition)
}

客户端模式配置 ​

CoApi 提供三种客户端模式以支持不同的编程范式。

客户端模式选项 ​

kotlin
enum class ClientMode {
    REACTIVE,   // WebClient 响应式客户端
    SYNC,       // RestClient 同步客户端  
    AUTO        // 基于 classpath 自动检测
}

模式检测逻辑 ​

AUTO 模式根据 Spring 框架的 classpath 智能选择合适的客户端:

kotlin
// From ClientMode.kt
private val INFERRED_MODE_BASED_ON_CLASS: ClientMode by lazy {
    try {
        Class.forName("org.springframework.web.reactive.HandlerResult")
        REACTIVE  // Spring WebFlux 可用
    } catch (ignore: ClassNotFoundException) {
        SYNC      // Spring MVC 可用
    }
}

fun inferClientMode(getProperty: (propertyKey: String) -> String?): ClientMode {
    val propertyValue = getProperty(COAPI_CLIENT_MODE_PROPERTY) ?: AUTO.name
    val mode = ClientMode.valueOf(propertyValue.uppercase())
    return if (mode == AUTO) {
        INFERRED_MODE_BASED_ON_CLASS
    } else {
        mode
    }
}

配置示例 ​

kotlin
// 强制响应式模式
@CoApi(clientMode = ClientMode.REACTIVE)
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}

// 强制同步模式
@CoApi(clientMode = ClientMode.SYNC)
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    List<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}

// 自动检测(默认)
@CoApi(clientMode = ClientMode.AUTO)
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}

负载均衡 ​

CoApi 与 Spring Cloud LoadBalancer 集成,提供客户端负载均衡能力。

负载均衡配置 ​

kotlin
@CoApi(serviceId = "github-service")
@LoadBalanced
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}

负载均衡协议支持 ​

CoApi 支持 lb:// 协议用于负载均衡服务:

kotlin
@CoApi(baseUrl = "lb://github-service")
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssue(@PathVariable String owner, @PathVariable String repo);
}

负载均衡实现 ​

负载均衡的客户端会得到一个内部的 Builder 定制器;只有当生效的定义是负载均衡时,工厂 Bean 才会应用它(因此 Spring Cloud 仍是可选依赖):

kotlin
// spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/LoadBalancedWebClientBuilderCustomizer.kt
internal class LoadBalancedWebClientBuilderCustomizer(
    private val beanFactory: BeanFactory
) : WebClientBuilderCustomizer {
    override fun customize(coApiDefinition: CoApiDefinition, builder: WebClient.Builder) {
        builder.filters { filters ->
            val hasLoadBalancedFilter = filters.any { filter ->
                filter is LoadBalancedExchangeFilterFunction || filter is DeferringLoadBalancerExchangeFilterFunction<*>
            }
            if (!hasLoadBalancedFilter) {
                filters.add(beanFactory.getBean(LoadBalancedExchangeFilterFunction::class.java))
            }
        }
    }
}
// 同步模式对应的 LoadBalancedRestClientBuilderCustomizer 会添加 BlockingLoadBalancerInterceptor。

认证 ​

CoApi 提供内置认证支持,具有可扩展的令牌提供程序。

Bearer Token 认证 ​

kotlin
@CoApi(baseUrl = "https://api.github.com")
interface GitHubApiClient {
    // Bearer token 自动添加到请求中
    @GetExchange("user")
    Mono<User> getCurrentUser()
}

认证组件 ​

  1. BearerTokenFilter:向请求头添加 Bearer 令牌
  2. ExpirableTokenProvider:提供带过期处理的令牌
  3. CachedExpirableTokenProvider:缓存令牌以提升性能
kotlin
// From BearerTokenFilter.kt
class BearerTokenFilter(tokenProvider: ExpirableTokenProvider) :
    HeaderSetFilter(
        headerName = HttpHeaders.AUTHORIZATION,
        headerValueProvider = tokenProvider,
        headerValueMapper = BearerHeaderValueMapper
    )

object BearerHeaderValueMapper : HeaderValueMapper {
    private const val BEARER_TOKEN_PREFIX = "Bearer "
    
    override fun map(headerValue: String): String {
        return "$BEARER_TOKEN_PREFIX$headerValue"
    }
}

Token Provider 实现 ​

kotlin
// spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/
interface ExpirableTokenProvider : HeaderValueProvider {
    fun getToken(): Mono<ExpirableToken>
}

class CachedExpirableTokenProvider @JvmOverloads constructor(
    tokenProvider: ExpirableTokenProvider,
    private val refreshBeforeExpiry: Duration = DEFAULT_REFRESH_BEFORE_EXPIRY // 60s
) : ExpirableTokenProvider {
    private val tokenCache: Mono<ExpirableToken> = tokenProvider.getToken()
        .cacheInvalidateIf { it.expiresWithin(refreshBeforeExpiry) }

    override fun getToken(): Mono<ExpirableToken> = tokenCache
}

第三部分:高效工作 ​

开发环境设置 ​

前置条件 ​

确保已安装以下软件:

  1. Java 17+:CoApi 需要 Java 17 或更高版本
  2. Kotlin 1.8+:现代 Kotlin 特性和协程
  3. Gradle 8.0+:构建自动化和依赖管理
  4. Git 2.30+:版本控制
  5. IDE:IntelliJ IDEA(推荐)或带 Kotlin 插件的 VS Code

IDE 设置 ​

IntelliJ IDEA:

  1. 安装 Kotlin 插件
  2. 在 IntelliJ 中打开项目
  3. 导入 Gradle 项目
  4. 配置 Kotlin SDK(JDK 17+)

VS Code:

bash
# Install recommended extensions
code --install-extension ms-kotlin.kotlin-extension-pack
code --install-extension ms-kotlin.kotlin-debugger
code --install-extension ms-python.python

构建环境配置 ​

bash
# Clone the repository
git clone https://github.com/Ahoo-Wang/CoApi.git
cd CoApi

# Set up Java 17
export JAVA_HOME=/path/to/java17
export PATH=$JAVA_HOME/bin:$PATH

# Configure Gradle (optional)
export GRADLE_OPTS="-Xmx2g -Dorg.gradle.daemon=true"

构建项目 ​

CoApi 使用 Gradle 和 Kotlin DSL 进行构建。项目采用多模块结构,不同组件有独立的模块。

构建命令 ​

bash
# Build all modules
./gradlew build

# Build specific module
./gradlew :spring:build
./gradlew :api:build
./gradlew :spring-boot-starter:build

# Run tests
./gradlew test

# Run tests for specific module
./gradlew :spring:test

# Run integration tests
./gradlew integrationTest

# Generate documentation
./gradlew javadoc

构建配置文件 ​

bash
# Development build
./gradlew build -Pprofile=dev

# Production build with optimization
./gradlew build -Pprofile=prod

# Build with specific Java version
./gradlew build -PtargetJavaVersion=17

模块结构构建 ​

每个模块可以独立构建:

bash
# Core API module
./gradlew :api:build

# Spring integration module  
./gradlew :spring:build

# Spring Boot starter
./gradlew :spring-boot-starter:build

# BOM (Bill of Materials)
./gradlew :bom:build

# Dependencies management
./gradlew :dependencies:build

测试策略 ​

CoApi 采用全面的测试策略,覆盖单元测试、集成测试和组件测试。

测试结构 ​

src/
├── test/kotlin/
│   ├── unit/               # 单元测试
│   │   ├── CoApiDefinitionTest.kt
│   │   └── ClientModeTest.kt
│   ├── integration/       # 集成测试
│   │   ├── EnableCoApiIntegrationTest.kt
│   │   └── LoadBalancingIntegrationTest.kt
│   └── component/         # 组件测试
│       ├── WebClientFactoryBeanTest.kt
│       └── RestClientFactoryBeanTest.kt

使用 FluentAssert 进行单元测试 ​

CoApi 使用 me.ahoo.test:fluent-assert-core 进行简洁、类型安全的断言:

kotlin
import me.ahoo.test.asserts.assert

@Test
fun `CoApiDefinition should resolve base URL correctly`() {
    val definition = TestApi::class.java.toCoApiDefinition(environment)
    
    assert(definition.name).isEqualTo("TestApi")
    assert(definition.baseUrl).isEqualTo("https://api.test.com")
    assert(definition.loadBalanced).isEqualTo(false)
}

集成测试 ​

集成测试使用 ApplicationContextRunner 测试 Spring 上下文设置:

kotlin
@Test
fun `EnableCoApi should register CoApi beans`() {
    ApplicationContextRunner()
        .withUserConfiguration(Application::class.java)
        .run { context ->
            val gitHubApiClient = context.getBean(GitHubApiClient::class.java)
            assert(gitHubApiClient).isNotNull()
        }
}

组件测试 ​

组件测试专注于单个组件:

kotlin
@Test
fun `WebClientFactoryBean should create WebClient`() {
    val factoryBean = WebClientFactoryBean(coApiDefinition)
    val webClient = factoryBean.getObject() as WebClient
    
    assert(webClient).isNotNull()
    assert(factoryBean.objectType).isEqualTo(GitHubApiClient::class.java)
}

使用 MockK 进行 Mock 测试 ​

kotlin
@Test
fun `GitHubApiClient should use mocked responses`() {
    val mockWebClient = mockk<WebClient>()
    val mockResponse = mockk<ResponseEntity<List<Issue>>>()
    
    every { mockResponse.body } returns listOf(Issue(1, "Test Issue"))
    
    coEvery { mockWebClient.get() } returns mockk {
        every { uri(any()) } returns this
        every { retrieve() } returns mockResponse
    }
    
    val api = GitHubApiClient(mockWebClient)
    val issues = api.getIssues()
    
    assert(issues).hasSize(1)
    assert(issues[0].title).isEqualTo("Test Issue")
}

代码质量与静态分析 ​

CoApi 通过静态分析、代码格式化和样式检查来执行高代码质量标准。

静态分析工具 ​

  1. Detekt:Kotlin 专用静态分析
  2. Ktlint:代码格式化和样式
  3. SpotBugs:Java 字节码分析
  4. JaCoCo:代码覆盖率

静态分析命令 ​

bash
# Run all static analysis
./gradlew check

# Run detekt
./gradlew detekt

# Run ktlint
./gradlew ktlintCheck

# Run spotbugs
./gradlew spotbugs

# Generate code coverage report
./gradlew jacocoTestReport

代码覆盖率标准 ​

CoApi 保持高代码覆盖率标准:

bash
# Minimum coverage requirements
./gradlew jacocoTestCoverageVerification

# HTML coverage report
./gradlew jacocoTestReport
open build/reports/jacoco/test/html/index.html

代码样式指南 ​

kotlin
// Use type-safe builders
@BeanDefinitionBuilder.genericBeanDefinition(WebClientFactoryBean::class.java)
    .addConstructorArgValue(coApiDefinition)

// Use extension functions
fun String.withBearerPrefix(): String = "Bearer $this"

// Use data classes for immutable data
data class CoApiDefinition(
    val name: String,
    val apiType: Class<*>,
    val baseUrl: String,
    val loadBalanced: Boolean
)

贡献指南 ​

CoApi 欢迎社区贡献。请遵循以下指南确保你的贡献符合项目标准。

贡献工作流程 ​

  1. Fork the Repository:创建你的分支
  2. Create Feature Branch:git checkout -b feature/your-feature
  3. Make Changes:实现你的更改
  4. Test Changes:运行 ./gradlew test
  5. Update Documentation:更新相关文档
  6. Submit Pull Request:使用 GitHub PR 模板

Pull Request 流程 ​

bash
# Create pull request template
# .github/PULL_REQUEST_TEMPLATE.md
---
## Summary
- Brief description of changes

## Changes Made
- List of changes

## Testing
- How changes were tested

## Breaking Changes
- List of breaking changes (if any)

## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] Code follows style guide
- [ ] CI checks pass

代码审查标准 ​

  1. Functionality:代码按预期工作
  2. Readability:清晰可维护的代码
  3. Performance:无性能回归
  4. Testing:全面的测试覆盖
  5. Documentation:更新且准确的文档

Bug 报告 ​

使用错误报告模板:

markdown
## Bug Description
- Clear description of the issue

## Steps to Reproduce
1. Step one
2. Step two
3. Step three

## Expected Behavior
- What should happen

## Actual Behavior
- What actually happens

## Environment
- CoApi version
- Spring Boot version
- Java version
- OS

发布流程 ​

CoApi 遵循语义化版本控制和自动化发布流程。

版本方案 ​

  • Major (X.0.0):破坏性变更
  • Minor (X.Y.0):新功能,向后兼容
  • Patch (X.Y.Z):错误修复,向后兼容

发布流程 ​

bash
# 1. Update version numbers
./gradlew bumpVersionMajor  # or bumpVersionMinor, bumpVersionPatch

# 2. Run release tests
./gradlew releaseTest

# 3. Create release tag
git tag v2.0.0

# 4. Push to Maven Central
./gradlew publish

# 5. Create GitHub release
git push origin v2.0.0

CI/CD Pipeline ​

yaml
# .github/workflows/release.yml
name: Release
on:
  push:
    tags: ['v*']

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
      - name: Publish to Maven Central
        run: ./gradlew publish
      - name: Create GitHub Release
        uses: actions/create-release@v1
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}

术语表 ​

核心概念 ​

  • @CoApi:将接口标记为 HTTP 客户端的主注解
  • @EnableCoApi:启用 CoApi 自动配置的注解
  • HttpInterface:Spring Framework 6 用于定义 HTTP 服务的特性
  • @HttpExchange:定义 HTTP 方法映射的注解
  • FactoryBean:用于创建对象的 Spring 接口
  • BeanDefinitionRegistry:用于注册 bean 定义的 Spring 接口

技术术语 ​

  • ClientMode:响应式与同步客户端的配置
  • CoApiDefinition:表示 CoApi 客户端的领域模型
  • LoadBalanced:启用客户端负载均衡的注解
  • WebClient:Spring 的响应式 HTTP 客户端
  • RestClient:Spring 的同步 HTTP 客户端
  • ExchangeFilterFunction:用于请求/响应处理的 WebClient 过滤器
  • HttpServiceProxyFactory:用于创建 HTTP 接口代理的工厂

架构术语 ​

  • Registrar:负责注册 bean 的组件
  • Proxy Pattern:用于创建动态代理的技术
  • Dependency Injection:用于提供依赖的模式
  • Auto-configuration:Spring Boot 的自动 bean 设置
  • Bean Factory:用于创建和管理 bean 的 Spring 组件

关键文件参考 ​

核心注解 ​

文件用途关键类
api/src/main/kotlin/me/ahoo/coapi/api/CoApi.ktHTTP 客户端主注解@CoApi
api/src/main/kotlin/me/ahoo/coapi/api/LoadBalanced.kt负载均衡注解@LoadBalanced

Spring 集成 ​

文件用途关键类
spring/src/main/kotlin/me/ahoo/coapi/spring/EnableCoApi.kt启用注解@EnableCoApi
spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.ktBean 注册CoApiRegistrar
spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiDefinition.kt领域模型CoApiDefinition
spring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt客户端模式配置ClientMode

HTTP 客户端实现 ​

文件用途关键类
spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/WebClientFactoryBean.ktWebClient 实现WebClientFactoryBean
spring/src/main/kotlin/me/ahoo/coapi/spring/client/sync/RestClientFactoryBean.ktRestClient 实现RestClientFactoryBean
spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiFactoryBean.kt代理工厂CoApiFactoryBean

认证 ​

文件用途关键类
spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/BearerTokenFilter.ktBearer 令牌认证BearerTokenFilter
spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/ExpirableTokenProvider.kt令牌提供程序接口ExpirableTokenProvider
spring/src/main/kotlin/me/ahoo/coapi/spring/client/reactive/auth/CachedExpirableTokenProvider.kt缓存令牌提供程序CachedExpirableTokenProvider

配置 ​

文件用途关键类
spring-boot-starter/src/main/kotlin/me/ahoo/coapi/spring/boot/AutoCoApiConfiguration.ktSpring Boot 自动配置AutoCoApiConfiguration
build.gradle.kts根构建配置Build script
settings.gradle.kts多模块设置Settings

跨语言对比 ​

CoApi vs OpenFeign ​

相似之处 ​

java
// OpenFeign
@FeignClient(name = "github", url = "https://api.github.com")
public interface GitHubApiClient {
    @GetMapping("/repos/{owner}/{repo}/issues")
    List<Issue> getIssues(@PathVariable("owner") String owner, @PathVariable("repo") String repo);
}

// CoApi
@CoApi(baseUrl = "https://api.github.com")
public interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    Flux<Issue> getIssues(@PathVariable String owner, @PathVariable String repo);
}

差异 ​

特性OpenFeignCoApi
编程模型仅同步响应式 + 同步
Spring 版本Spring 5/6仅 Spring 6
HTTP Interface自定义实现原生 Spring HTTP Interface
负载均衡通过 Ribbon/Spring Cloud LoadBalancer直接集成
响应式支持有限完整 Project Reactor 支持

CoApi vs Retrofit ​

相似之处 ​

kotlin
// Retrofit
@GET("/repos/{owner}/{repo}/issues")
suspend fun getIssues(
    @Path("owner") owner: String,
    @Path("repo") repo: String
): List<Issue>

// CoApi
@GetExchange("repos/{owner}/{repo}/issues")
suspend fun getIssues(
    @PathVariable String owner,
    @PathVariable String repo
): Flux<Issue>

差异 ​

特性RetrofitCoApi
框架集成独立库Spring Framework 集成
依赖注入手动通过 Spring DI 自动
配置构建器模式注解 + 自动配置
响应式支持通过协程原生 Spring 响应式
负载均衡手动实现内置支持

CoApi vs WebClient/RestClient ​

直接使用 ​

kotlin
// Direct WebClient
val webClient = WebClient.builder()
    .baseUrl("https://api.github.com")
    .build()

val issues = webClient.get()
    .uri("/repos/{owner}/{repo}/issues", "Ahoo-Wang", "CoApi")
    .retrieve()
    .bodyToFlux<Issue>()
    .collectList()
    .block()

// Direct RestClient
val restClient = RestClient.builder()
    .baseUrl("https://api.github.com")
    .build()

val issues = restClient.get()
    .uri("/repos/{owner}/{repo}/issues", "Ahoo-Wang", "CoApi")
    .retrieve()
    .bodyToFlux<Issue>()
    .collectList()
    .block()

CoApi 优势 ​

kotlin
// CoApi - 零样板
@CoApi(baseUrl = "https://api.github.com")
interface GitHubApiClient {
    @GetExchange("repos/{owner}/{repo}/issues")
    fun getIssues(@PathVariable owner: String, @PathVariable repo: String): Flux<Issue>
}

// Usage
@Autowired lateinit var gitHubApiClient: GitHubApiClient
val issues = gitHubApiClient.getIssues("Ahoo-Wang", "CoApi")

功能对比矩阵 ​

特性CoApiOpenFeignRetrofitWebClientRestClient
自动配置是是否否否
响应式支持是否是是否
同步支持是是是否是
类型安全是是是是是
Spring 集成是是是是是
负载均衡是是否是是
内置认证是是否否否
错误处理是是是是是
Mock 支持是是是是是
文档是是是是是

附录 ​

附录 A:配置属性 ​

CoApi 属性 ​

properties
# Client mode configuration
coapi.mode=REACTIVE|SYNC|AUTO

# Base URL configuration for serviceId resolution
github.url=https://api.github.com

# Load balancing configuration
spring.cloud.loadbalancer.ribbon.enabled=false

属性参考 ​

属性默认值描述
coapi.modeAUTO客户端模式:REACTIVE、SYNC 或 AUTO
spring.cloud.loadbalancer.ribbon.enabledfalse使用 Spring Cloud LoadBalancer 时禁用 Ribbon

附录 B:常见模式 ​

1. API 契约模式 ​

kotlin
// Shared API contract
@HttpExchange("todo")
interface TodoApi {
    @GetExchange
    fun getTodo(): Flux<Todo>
    
    @PostExchange
    fun createTodo(@RequestBody todo: Todo): Mono<Todo>
}

// Client implementation
@CoApi(serviceId = "todo-service")
interface TodoClient : TodoApi

// Server implementation
@RestController
class TodoController : TodoApi {
    override fun getTodo(): Flux<Todo> = Flux.just(Todo(1, "Learn CoApi"))
}

2. 认证模式 ​

kotlin
@CoApi(baseUrl = "https://api.github.com")
class GitHubApiClient(
    private val tokenProvider: ExpirableTokenProvider
) {
    // Bearer token 自动添加
    @GetExchange("user")
    fun getCurrentUser(): Mono<User> = Mono.just(User("test"))
}

3. 负载均衡模式 ​

kotlin
@CoApi(serviceId = "user-service")
@LoadBalanced
interface UserApiClient {
    @GetExchange("users/{id}")
    fun getUser(@PathVariable id: String): Mono<User>
    
    @GetExchange("users")
    fun getAllUsers(): Flux<User>
}

附录 C:故障排除 ​

常见问题 ​

  1. Bean 未注册

    bash
    # Check @EnableCoApi annotation
    @EnableCoApi(clients = [GitHubApiClient::class])
    @SpringBootApplication
    class Application
  2. 客户端模式问题

    bash
    # Explicitly set client mode
    @CoApi(clientMode = ClientMode.REACTIVE)
    interface GitHubApiClient
  3. 负载均衡不工作

    bash
    # Ensure Spring Cloud LoadBalancer dependency
    implementation("org.springframework.cloud:spring-cloud-starter-loadbalancer")
  4. 认证问题

    bash
    # Check token provider configuration
    @Bean
    fun tokenProvider(): ExpirableTokenProvider {
        return CachedExpirableTokenProvider(SimpleTokenProvider())
    }

调试模式 ​

kotlin
// Enable debug logging
logging.level.me.ahoo.coapi=DEBUG

// Enable Spring debug
logging.level.org.springframework.web.reactive=DEBUG

性能调优 ​

kotlin
// WebClient performance configuration
@Bean
fun webClient(): WebClient {
    return WebClient.builder()
        .codecs { configurer ->
            configurer.defaultCodecs.maxInMemorySize(16 * 1024 * 1024)
        }
        .build()
}

以上就是 CoApi 贡献者指南的全部内容。本指南提供了项目的全面概述,从语言基础到高级功能和贡献最佳实践。无论你是探索代码库的新开发者还是有经验的贡献者,本指南都将帮助你理解和有效地使用 CoApi。