Skip to content

Spring Cloud 2021.0.x (Jubilee) 版本

官方介绍

Spring Cloud 2021.0.x (代号 Jubilee) 是 Spring Cloud 的重要版本,于 2021 年底发布。该版本基于 Spring Boot 2.6.x 构建,继续推进微服务架构的现代化和云原生化,引入了更多对响应式编程、可观测性、安全性等方面的增强支持。

Jubilee 版本特别关注了微服务架构中的可观测性,集成了最新的分布式追踪、指标收集和日志聚合技术,为现代云原生应用提供了完整的可观测性解决方案。

版本特性

1. Spring Cloud Gateway 3.1.x

  • 增强的路由配置 DSL
  • 更好的性能优化
  • 改进的安全过滤器链

2. Spring Cloud LoadBalancer 增强

  • 支持请求级别的负载均衡策略
  • 更好的重试和熔断集成
  • 改进的健康检查机制

3. Spring Cloud Sleuth 更新 (现为 Spring Cloud Zipkin)

  • 更好的 OpenTelemetry 集成
  • 改进的分布式追踪性能
  • 更灵活的采样策略

4. Spring Cloud Contract 增强

  • 支持异步契约测试
  • 更好的消息传递契约支持
  • 改进的契约验证流程

5. 安全性增强

  • 集成 Spring Security 5.6+
  • 更好的 OAuth2/OIDC 支持
  • 增强的证书管理和密钥轮换

官方获取地址

Maven 依赖

xml
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Gradle 依赖

gradle
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.8"
    }
}

官方文档

环境要求

  • Java 11 或更高版本 (Java 17+ 推荐)
  • Spring Boot 2.6.x 或 2.7.x
  • Maven 3.5+ 或 Gradle 7.0+
  • 推荐使用 Spring Boot 2.7.18 以获得最佳兼容性

部署方法

1. 创建 Spring Cloud 2021.0.x 项目

bash
# 使用 Spring Initializr 创建项目
curl https://start.spring.io/starter.tgz \
  -d groupId=com.example \
  -d artifactId=spring-cloud-jubilee-service \
  -d name=jubilee-service \
  -d packaging=jar \
  -d bootVersion=2.7.18 \
  -d javaVersion=11 \
  -d language=java \
  -d type=maven-project \
  -d baseDir=jubilee-service \
  -d packageName=com.example \
  -d dependencies=cloud-gateway,cloud-discovery,cloud-config-client,cloud-circuit-breaker-reactive \
  | tar -xzvf -

2. 配置 API 网关

java
package com.example.jubilee.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("user-service", r -> r.path("/users/**")
                        .filters(f -> f.stripPrefix(1)
                                .retry(3))
                        .uri("lb://USER-SERVICE"))
                .route("order-service", r -> r.path("/orders/**")
                        .filters(f -> f.stripPrefix(1)
                                .circuitBreaker(c -> c.setName("orderCircuitBreaker")
                                        .setFallbackUri("forward:/fallback")))
                        .uri("lb://ORDER-SERVICE"))
                .build();
    }
}

application.yml:

yaml
server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/users/**
          filters:
            - StripPrefix=1
            - name: CircuitBreaker
              args:
                name: userServiceCB
                fallbackUri: forward:/user-fallback
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/orders/**
          filters:
            - StripPrefix=1
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
    consul:
      host: localhost
      port: 8500

resilience4j:
  circuitbreaker:
    instances:
      userServiceCB:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
      orderCircuitBreaker:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s

management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://zipkin:9411/api/v2/spans

logging:
  pattern:
    level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}]"

3. 部署到容器

Dockerfile:

dockerfile
FROM eclipse-temurin:17-jre-alpine
VOLUME /tmp
COPY target/jubilee-service.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
bash
# 构建 Docker 镜像
docker build -t spring-cloud-jubilee:2021.0.x .

# 运行服务
docker run -d -p 8080:8080 \
  -e SPRING_CLOUD_CONSUL_HOST=consul \
  -e SPRING_CLOUD_CONSUL_PORT=8500 \
  spring-cloud-jubilee:2021.0.x

二次开发

1. 自定义全局过滤器

java
package com.example.jubilee.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long startTime = System.currentTimeMillis();
        
        return chain.filter(exchange).doFinally(signalType -> {
            long duration = System.currentTimeMillis() - startTime;
            String path = exchange.getRequest().getURI().getPath();
            String method = exchange.getRequest().getMethodValue();
            
            System.out.printf("Request %s %s took %d ms%n", method, path, duration);
        });
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

2. 自定义熔断器配置

java
package com.example.jubilee.circuitbreaker;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
public class CircuitBreakerConfiguration {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .circuitBreakerConfig(CircuitBreakerConfig.custom()
                        .slidingWindowSize(100)
                        .failureRateThreshold(50)
                        .waitDurationInOpenState(Duration.ofSeconds(10))
                        .permittedNumberOfCallsInHalfOpenState(10)
                        .build())
                .timeLimiterConfig(TimeLimiterConfig.custom()
                        .timeoutDuration(Duration.ofSeconds(4))
                        .build())
                .build());
    }
}

配置示例

1. 微服务配置

application.yml:

yaml
server:
  port: 8081

spring:
  application:
    name: jubilee-microservice
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
        prefer-ip-address: true
        instance-id: ${spring.application.name}:${random.value}
    config:
      discovery:
        enabled: true
        service-id: config-server
  config:
    import: optional:consul:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,httpexchanges,refresh
  endpoint:
    health:
      show-details: when-authorized
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans

resilience4j:
  circuitbreaker:
    instances:
      backendA:
        sliding-window-size: 100
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permittedNumberOfCallsInHalfOpenState: 10
  retry:
    instances:
      backendA:
        max-attempts: 3
        wait-duration: 1s
  bulkhead:
    instances:
      backendA:
        max-concurrent-calls: 10
  thread-pool-bulkhead:
    instances:
      backendA:
        max-thread-pool-size: 2
        core-thread-pool-size: 1
        queue-capacity: 1

logging:
  pattern:
    level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}]"
  level:
    org.springframework.cloud: DEBUG
    org.springframework.web: DEBUG
    com.example: INFO

2. 分布式追踪配置

application.yml:

yaml
management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://zipkin:9411/api/v2/spans
    service:
      name: jubilee-service
  
spring:
  sleuth:
    sampler:
      probability: 1.0
    propagation:
      type: B3
    baggage:
      correlation-enabled: true
      remote-fields:
        - my-baggage-field
      tag-fields:
        - my-tag-field

参考资源

版本历史

  • 2021.0.0-M1 (2021-05-20): 初始里程碑版本
  • 2021.0.0-RC1 (2021-09-02): 第一个候选发布版本
  • 2021.0.0 (2021-11-16): 正式发布版本 (Jubilee)
  • 2021.0.1-2021.0.8 (2021-12-20 至 2023-02-08): 各个小版本修复更新