Java学习第15天 - 服务网关与API管理

学习时间: 4-5小时
学习目标: 掌握Spring Cloud Gateway的使用,学会构建API网关和路由管理


详细学习清单


✅ 第一部分:API网关基础概念(60分钟)

1. 网关的作用与特点

网关核心功能

diff 复制代码
- 路由转发:将请求路由到不同的微服务
- 负载均衡:在多个服务实例间分发请求
- 安全认证:统一的安全控制和权限验证
- 限流熔断:保护后端服务不被过载
- 日志监控:统一的请求日志和监控
- 协议转换:支持不同协议间的转换

网关架构图

java 复制代码
// GatewayArchitecture.java
package com.example.demo.gateway;

public class GatewayArchitecture {
    
    public static void main(String[] args) {
        System.out.println("=== API网关架构组件 ===");
        System.out.println("1. 客户端请求 → API网关");
        System.out.println("2. 网关路由 → 微服务");
        System.out.println("3. 网关过滤 → 请求/响应处理");
        System.out.println("4. 网关聚合 → 多个服务响应");
        System.out.println("5. 网关监控 → 性能指标收集");
    }
}

2. 网关设计模式

网关设计模式

java 复制代码
// GatewayPatterns.java
package com.example.demo.gateway;

import java.util.List;
import java.util.ArrayList;

public class GatewayPatterns {
    
    public static class GatewayPattern {
        private String name;
        private String description;
        private List<String> useCases;
        private List<String> advantages;
        
        public GatewayPattern(String name, String description) {
            this.name = name;
            this.description = description;
            this.useCases = new ArrayList<>();
            this.advantages = new ArrayList<>();
        }
        
        public void addUseCase(String useCase) {
            this.useCases.add(useCase);
        }
        
        public void addAdvantage(String advantage) {
            this.advantages.add(advantage);
        }
        
        // Getter方法
        public String getName() { return name; }
        public String getDescription() { return description; }
        public List<String> getUseCases() { return useCases; }
        public List<String> getAdvantages() { return advantages; }
    }
    
    public static void main(String[] args) {
        // 路由模式
        GatewayPattern routingPattern = new GatewayPattern("路由模式", "根据请求路径将请求路由到不同服务");
        routingPattern.addUseCase("微服务路由");
        routingPattern.addUseCase("版本控制");
        routingPattern.addUseCase("A/B测试");
        routingPattern.addAdvantage("灵活的路由配置");
        routingPattern.addAdvantage("支持动态路由");
        
        // 聚合模式
        GatewayPattern aggregationPattern = new GatewayPattern("聚合模式", "将多个微服务的响应聚合为一个响应");
        aggregationPattern.addUseCase("用户信息聚合");
        aggregationPattern.addUseCase("订单详情聚合");
        aggregationPattern.addUseCase("仪表板数据聚合");
        aggregationPattern.addAdvantage("减少客户端请求");
        aggregationPattern.addAdvantage("提升用户体验");
        
        // 过滤模式
        GatewayPattern filterPattern = new GatewayPattern("过滤模式", "在请求处理过程中添加通用逻辑");
        filterPattern.addUseCase("认证授权");
        filterPattern.addUseCase("日志记录");
        filterPattern.addUseCase("限流熔断");
        filterPattern.addAdvantage("代码复用");
        filterPattern.addAdvantage("统一处理");
        
        System.out.println("=== 网关设计模式 ===");
        printGatewayPattern(routingPattern);
        printGatewayPattern(aggregationPattern);
        printGatewayPattern(filterPattern);
    }
    
    private static void printGatewayPattern(GatewayPattern pattern) {
        System.out.println("\n模式名称: " + pattern.getName());
        System.out.println("模式描述: " + pattern.getDescription());
        System.out.println("使用场景:");
        for (String useCase : pattern.getUseCases()) {
            System.out.println("  - " + useCase);
        }
        System.out.println("优势特点:");
        for (String advantage : pattern.getAdvantages()) {
            System.out.println("  - " + advantage);
        }
    }
}

✅ 第二部分:Spring Cloud Gateway配置(90分钟)

1. 网关服务配置

网关服务pom.xml

xml 复制代码
<!-- gateway-service/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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>microservice-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>gateway-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
</project>

网关服务主类

java 复制代码
// GatewayApplication.java
package com.example.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

网关服务配置

yaml 复制代码
# gateway-service/src/main/resources/application.yml
server:
  port: 8080

spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        # 用户服务路由
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY
        
        # 订单服务路由
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 5
                redis-rate-limiter.burstCapacity: 10
        
        # 商品服务路由
        - id: product-service-route
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
          filters:
            - StripPrefix=1
        
        # 支付服务路由
        - id: payment-service-route
          uri: lb://payment-service
          predicates:
            - Path=/api/payments/**
          filters:
            - StripPrefix=1
        
        # 文件服务路由
        - id: file-service-route
          uri: lb://file-service
          predicates:
            - Path=/api/files/**
          filters:
            - StripPrefix=1
        
        # 通知服务路由
        - id: notification-service-route
          uri: lb://notification-service
          predicates:
            - Path=/api/notifications/**
          filters:
            - StripPrefix=1

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

management:
  endpoints:
    web:
      exposure:
        include: health,info,gateway
  endpoint:
    health:
      show-details: always

# Redis配置
spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    timeout: 2000ms
    lettuce:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0

2. 自定义过滤器

全局认证过滤器

java 复制代码
// GlobalAuthFilter.java
package com.example.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    // 不需要认证的路径
    private static final List<String> WHITE_LIST = Arrays.asList(
        "/api/auth/login",
        "/api/auth/register",
        "/api/auth/refresh",
        "/api/public/**",
        "/actuator/**"
    );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        
        // 检查是否是白名单路径
        if (isWhiteListPath(path)) {
            return chain.filter(exchange);
        }
        
        // 获取Authorization头
        String token = getTokenFromRequest(request);
        
        if (!StringUtils.hasText(token)) {
            return unauthorized(exchange, "缺少认证令牌");
        }
        
        // 验证token(这里简化处理,实际应该调用认证服务)
        if (!isValidToken(token)) {
            return unauthorized(exchange, "无效的认证令牌");
        }
        
        // 添加用户信息到请求头
        ServerHttpRequest modifiedRequest = request.mutate()
                .header("X-User-Id", getUserIdFromToken(token))
                .header("X-User-Roles", getUserRolesFromToken(token))
                .build();
        
        return chain.filter(exchange.mutate().request(modifiedRequest).build());
    }

    @Override
    public int getOrder() {
        return -100; // 高优先级
    }
    
    private boolean isWhiteListPath(String path) {
        return WHITE_LIST.stream().anyMatch(path::startsWith);
    }
    
    private String getTokenFromRequest(ServerHttpRequest request) {
        String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
    
    private boolean isValidToken(String token) {
        // 这里应该调用认证服务验证token
        // 简化实现,实际项目中需要集成JWT验证
        return StringUtils.hasText(token) && token.length() > 10;
    }
    
    private String getUserIdFromToken(String token) {
        // 从token中解析用户ID
        // 简化实现,实际应该解析JWT
        return "user123";
    }
    
    private String getUserRolesFromToken(String token) {
        // 从token中解析用户角色
        // 简化实现,实际应该解析JWT
        return "USER,ADMIN";
    }
    
    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
}

请求日志过滤器

java 复制代码
// RequestLogFilter.java
package com.example.gateway.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
public class RequestLogFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(RequestLogFilter.class);
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        String method = request.getMethod().name();
        String remoteAddress = request.getRemoteAddress() != null ? 
                request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
        
        long startTime = System.currentTimeMillis();
        
        logger.info("=== 请求开始 ===");
        logger.info("时间: {}", LocalDateTime.now().format(formatter));
        logger.info("路径: {} {}", method, path);
        logger.info("来源IP: {}", remoteAddress);
        logger.info("请求头: {}", request.getHeaders());
        
        return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> {
                    long endTime = System.currentTimeMillis();
                    long duration = endTime - startTime;
                    
                    logger.info("=== 请求结束 ===");
                    logger.info("响应状态: {}", exchange.getResponse().getStatusCode());
                    logger.info("处理时间: {}ms", duration);
                    logger.info("时间: {}", LocalDateTime.now().format(formatter));
                    logger.info("================\n");
                }));
    }

    @Override
    public int getOrder() {
        return -200; // 最高优先级,最先执行
    }
}

限流过滤器

java 复制代码
// RateLimitFilter.java
package com.example.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

@Component
public class RateLimitFilter extends AbstractGatewayFilterFactory<RateLimitFilter.Config> {

    public RateLimitFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String key = getClientKey(exchange);
            
            if (isAllowed(key, config)) {
                return chain.filter(exchange);
            } else {
                return tooManyRequests(exchange);
            }
        };
    }

    private String getClientKey(ServerWebExchange exchange) {
        // 基于IP地址的限流
        String clientIp = exchange.getRequest().getRemoteAddress() != null ?
                exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
        return "rate_limit:" + clientIp;
    }

    private boolean isAllowed(String key, Config config) {
        // 这里应该使用Redis实现分布式限流
        // 简化实现,使用内存计数器
        AtomicInteger counter = counters.get(key);
        if (counter == null) {
            counter = new AtomicInteger(0);
            counters.put(key, counter);
        }
        
        long now = System.currentTimeMillis();
        if (now - lastResetTime.get() > config.getTimeWindow()) {
            counter.set(0);
            lastResetTime.set(now);
        }
        
        return counter.incrementAndGet() <= config.getMaxRequests();
    }

    private Mono<Void> tooManyRequests(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        
        String message = "{\"error\":\"请求过于频繁,请稍后重试\",\"code\":\"RATE_LIMIT_EXCEEDED\"}";
        DataBuffer buffer = response.bufferFactory().wrap(message.getBytes(StandardCharsets.UTF_8));
        
        return response.writeWith(Mono.just(buffer));
    }

    // 内存计数器(实际项目中应该使用Redis)
    private static final java.util.Map<String, AtomicInteger> counters = new java.util.concurrent.ConcurrentHashMap<>();
    private static final AtomicLong lastResetTime = new AtomicLong(System.currentTimeMillis());

    public static class Config {
        private int maxRequests = 100;
        private long timeWindow = 60000; // 1分钟

        public int getMaxRequests() { return maxRequests; }
        public void setMaxRequests(int maxRequests) { this.maxRequests = maxRequests; }

        public long getTimeWindow() { return timeWindow; }
        public void setTimeWindow(long timeWindow) { this.timeWindow = timeWindow; }
    }
}

✅ 第三部分:网关路由管理(90分钟)

1. 动态路由配置

路由配置管理

java 复制代码
// RouteConfigManager.java
package com.example.gateway.route;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class RouteConfigManager {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    
    private final Map<String, RouteDefinition> routeCache = new ConcurrentHashMap<>();

    /**
     * 添加路由
     */
    public Mono<Void> addRoute(RouteDefinition routeDefinition) {
        routeCache.put(routeDefinition.getId(), routeDefinition);
        return routeDefinitionWriter.save(Mono.just(routeDefinition));
    }

    /**
     * 更新路由
     */
    public Mono<Void> updateRoute(RouteDefinition routeDefinition) {
        routeCache.put(routeDefinition.getId(), routeDefinition);
        return routeDefinitionWriter.save(Mono.just(routeDefinition));
    }

    /**
     * 删除路由
     */
    public Mono<Void> deleteRoute(String routeId) {
        routeCache.remove(routeId);
        return routeDefinitionWriter.delete(Mono.just(routeId));
    }

    /**
     * 获取所有路由
     */
    public List<RouteDefinition> getAllRoutes() {
        return routeCache.values().stream().toList();
    }

    /**
     * 根据ID获取路由
     */
    public RouteDefinition getRouteById(String routeId) {
        return routeCache.get(routeId);
    }

    /**
     * 刷新路由
     */
    public Mono<Void> refreshRoutes() {
        // 清除所有路由
        routeCache.values().forEach(route -> 
            routeDefinitionWriter.delete(Mono.just(route.getId())));
        
        // 重新添加所有路由
        return Mono.when(
            routeCache.values().stream()
                .map(routeDefinitionWriter::save)
                .map(mono -> mono.then())
                .toList()
        );
    }
}

路由配置实体

java 复制代码
// RouteConfig.java
package com.example.gateway.route;

import java.util.List;
import java.util.Map;

public class RouteConfig {
    
    private String id;
    private String name;
    private String description;
    private String uri;
    private List<String> predicates;
    private List<FilterConfig> filters;
    private int order;
    private boolean enabled;
    private Map<String, Object> metadata;

    // 构造函数
    public RouteConfig() {}

    public RouteConfig(String id, String name, String uri) {
        this.id = id;
        this.name = name;
        this.uri = uri;
        this.enabled = true;
    }

    // Getter和Setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }

    public String getUri() { return uri; }
    public void setUri(String uri) { this.uri = uri; }

    public List<String> getPredicates() { return predicates; }
    public void setPredicates(List<String> predicates) { this.predicates = predicates; }

    public List<FilterConfig> getFilters() { return filters; }
    public void setFilters(List<FilterConfig> filters) { this.filters = filters; }

    public int getOrder() { return order; }
    public void setOrder(int order) { this.order = order; }

    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }

    public Map<String, Object> getMetadata() { return metadata; }
    public void setMetadata(Map<String, Object> metadata) { this.metadata = metadata; }

    public static class FilterConfig {
        private String name;
        private Map<String, Object> args;

        public FilterConfig() {}

        public FilterConfig(String name, Map<String, Object> args) {
            this.name = name;
            this.args = args;
        }

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }

        public Map<String, Object> getArgs() { return args; }
        public void setArgs(Map<String, Object> args) { this.args = args; }
    }
}

2. 路由管理控制器

路由管理Controller

java 复制代码
// RouteManagementController.java
package com.example.gateway.controller;

import com.example.gateway.route.RouteConfig;
import com.example.gateway.route.RouteConfigManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/gateway/routes")
public class RouteManagementController {

    @Autowired
    private RouteConfigManager routeConfigManager;

    /**
     * 获取所有路由配置
     */
    @GetMapping
    public ResponseEntity<List<RouteConfig>> getAllRoutes() {
        List<RouteConfig> routes = routeConfigManager.getAllRoutes();
        return ResponseEntity.ok(routes);
    }

    /**
     * 根据ID获取路由配置
     */
    @GetMapping("/{routeId}")
    public ResponseEntity<RouteConfig> getRouteById(@PathVariable String routeId) {
        RouteConfig route = routeConfigManager.getRouteById(routeId);
        if (route != null) {
            return ResponseEntity.ok(route);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * 创建新路由
     */
    @PostMapping
    public ResponseEntity<Void> createRoute(@RequestBody RouteConfig routeConfig) {
        try {
            routeConfigManager.addRoute(convertToRouteDefinition(routeConfig));
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 更新路由配置
     */
    @PutMapping("/{routeId}")
    public ResponseEntity<Void> updateRoute(@PathVariable String routeId, 
                                         @RequestBody RouteConfig routeConfig) {
        try {
            routeConfig.setId(routeId);
            routeConfigManager.updateRoute(convertToRouteDefinition(routeConfig));
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 删除路由
     */
    @DeleteMapping("/{routeId}")
    public ResponseEntity<Void> deleteRoute(@PathVariable String routeId) {
        try {
            routeConfigManager.deleteRoute(routeId);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 启用/禁用路由
     */
    @PatchMapping("/{routeId}/status")
    public ResponseEntity<Void> updateRouteStatus(@PathVariable String routeId, 
                                               @RequestParam boolean enabled) {
        try {
            RouteConfig route = routeConfigManager.getRouteById(routeId);
            if (route != null) {
                route.setEnabled(enabled);
                routeConfigManager.updateRoute(convertToRouteDefinition(route));
                return ResponseEntity.ok().build();
            } else {
                return ResponseEntity.notFound().build();
            }
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    /**
     * 刷新所有路由
     */
    @PostMapping("/refresh")
    public ResponseEntity<Void> refreshRoutes() {
        try {
            routeConfigManager.refreshRoutes();
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 获取路由统计信息
     */
    @GetMapping("/stats")
    public ResponseEntity<Map<String, Object>> getRouteStats() {
        List<RouteConfig> routes = routeConfigManager.getAllRoutes();
        
        long totalRoutes = routes.size();
        long enabledRoutes = routes.stream().filter(RouteConfig::isEnabled).count();
        long disabledRoutes = totalRoutes - enabledRoutes;
        
        Map<String, Object> stats = Map.of(
            "totalRoutes", totalRoutes,
            "enabledRoutes", enabledRoutes,
            "disabledRoutes", disabledRoutes
        );
        
        return ResponseEntity.ok(stats);
    }

    /**
     * 将RouteConfig转换为RouteDefinition
     */
    private org.springframework.cloud.gateway.route.RouteDefinition convertToRouteDefinition(RouteConfig config) {
        // 这里需要实现转换逻辑
        // 简化实现,实际项目中需要完整的转换
        return new org.springframework.cloud.gateway.route.RouteDefinition();
    }
}

✅ 第四部分:网关监控与聚合(60分钟)

1. 网关监控配置

监控配置类

java 复制代码
// GatewayMonitoringConfig.java
package com.example.gateway.config;

import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayMonitoringConfig {

    @Bean
    public HttpTraceRepository httpTraceRepository() {
        return new InMemoryHttpTraceRepository();
    }

    @Bean
    public MeterRegistry meterRegistry() {
        return io.micrometer.core.instrument.Metrics.globalRegistry;
    }
}

2. 服务聚合

用户信息聚合服务

java 复制代码
// UserInfoAggregationService.java
package com.example.gateway.service;

import com.example.gateway.dto.UserInfoDTO;
import com.example.gateway.dto.OrderSummaryDTO;
import com.example.gateway.dto.ProductHistoryDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.List;

@Service
public class UserInfoAggregationService {

    @Autowired
    private WebClient.Builder webClientBuilder;

    /**
     * 聚合用户完整信息
     */
    public Mono<UserInfoDTO> aggregateUserInfo(Long userId) {
        return Mono.zip(
            getUserBasicInfo(userId),
            getUserOrders(userId),
            getUserProductHistory(userId)
        ).map(tuple -> {
            UserInfoDTO userInfo = tuple.getT1();
            userInfo.setOrderSummary(tuple.getT2());
            userInfo.setProductHistory(tuple.getT3());
            return userInfo;
        });
    }

    /**
     * 获取用户基本信息
     */
    private Mono<UserInfoDTO> getUserBasicInfo(Long userId) {
        return webClientBuilder.build()
                .get()
                .uri("http://user-service/api/users/{userId}", userId)
                .retrieve()
                .bodyToMono(UserInfoDTO.class);
    }

    /**
     * 获取用户订单摘要
     */
    private Mono<OrderSummaryDTO> getUserOrders(Long userId) {
        return webClientBuilder.build()
                .get()
                .uri("http://order-service/api/orders/user/{userId}/summary", userId)
                .retrieve()
                .bodyToMono(OrderSummaryDTO.class);
    }

    /**
     * 获取用户商品历史
     */
    private Mono<ProductHistoryDTO> getUserProductHistory(Long userId) {
        return webClientBuilder.build()
                .get()
                .uri("http://product-service/api/products/user/{userId}/history", userId)
                .retrieve()
                .bodyToMono(ProductHistoryDTO.class);
    }
}

聚合数据DTO

java 复制代码
// UserInfoDTO.java
package com.example.gateway.dto;

import java.time.LocalDateTime;
import java.util.List;

public class UserInfoDTO {
    
    private Long id;
    private String username;
    private String email;
    private String firstName;
    private String lastName;
    private String phone;
    private Boolean enabled;
    private LocalDateTime createdAt;
    private OrderSummaryDTO orderSummary;
    private ProductHistoryDTO productHistory;

    // 构造函数
    public UserInfoDTO() {}

    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }

    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }

    public Boolean getEnabled() { return enabled; }
    public void setEnabled(Boolean enabled) { this.enabled = enabled; }

    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }

    public OrderSummaryDTO getOrderSummary() { return orderSummary; }
    public void setOrderSummary(OrderSummaryDTO orderSummary) { this.orderSummary = orderSummary; }

    public ProductHistoryDTO getProductHistory() { return productHistory; }
    public void setProductHistory(ProductHistoryDTO productHistory) { this.productHistory = productHistory; }

    public static class OrderSummaryDTO {
        private Long totalOrders;
        private Double totalAmount;
        private List<RecentOrderDTO> recentOrders;

        public Long getTotalOrders() { return totalOrders; }
        public void setTotalOrders(Long totalOrders) { this.totalOrders = totalOrders; }

        public Double getTotalAmount() { return totalAmount; }
        public void setTotalAmount(Double totalAmount) { this.totalAmount = totalAmount; }

        public List<RecentOrderDTO> getRecentOrders() { return recentOrders; }
        public void setRecentOrders(List<RecentOrderDTO> recentOrders) { this.recentOrders = recentOrders; }
    }

    public static class ProductHistoryDTO {
        private Long totalProducts;
        private List<RecentProductDTO> recentProducts;

        public Long getTotalProducts() { return totalProducts; }
        public void setTotalProducts(Long totalProducts) { this.totalProducts = totalProducts; }

        public List<RecentProductDTO> getRecentProducts() { return recentProducts; }
        public void setRecentProducts(List<RecentProductDTO> recentProducts) { this.recentProducts = recentProducts; }
    }

    public static class RecentOrderDTO {
        private Long id;
        private String orderNumber;
        private Double amount;
        private String status;
        private LocalDateTime createdAt;

        // Getter和Setter方法
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }

        public String getOrderNumber() { return orderNumber; }
        public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }

        public Double getAmount() { return amount; }
        public void setAmount(Double amount) { this.amount = amount; }

        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }

        public LocalDateTime getCreatedAt() { return createdAt; }
        public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    }

    public static class RecentProductDTO {
        private Long id;
        private String name;
        private String category;
        private LocalDateTime lastViewed;

        // Getter和Setter方法
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }

        public String getCategory() { return category; }
        public void setCategory(String category) { this.category = category; }

        public LocalDateTime getLastViewed() { return lastViewed; }
        public void setLastViewed(LocalDateTime lastViewed) { this.lastViewed = lastViewed; }
    }
}

🎯 今日学习总结

1. 掌握的核心技能

  • ✅ API网关架构设计
  • ✅ Spring Cloud Gateway配置
  • ✅ 自定义过滤器开发
  • ✅ 动态路由管理
  • ✅ 服务聚合与监控

2. 网关核心功能

  • 路由转发:智能路由到不同微服务
  • 安全认证:统一的权限控制
  • 限流熔断:保护后端服务
  • 日志监控:统一的请求追踪
  • 服务聚合:减少客户端请求

3. Spring Cloud Gateway特点

  • 高性能:基于WebFlux响应式编程
  • 灵活配置:支持动态路由配置
  • 丰富过滤器:内置多种过滤器
  • 监控完善:集成Actuator监控
  • 扩展性强:支持自定义过滤器

4. 下一步学习方向

  • 分布式事务管理
  • 服务监控与追踪
  • 容器化部署
  • 微服务测试策略
  • 性能优化与调优

学习建议

  1. 架构理解:深入理解网关在微服务架构中的作用
  2. 过滤器开发:学会开发自定义过滤器处理通用逻辑
  3. 路由管理:掌握动态路由配置和管理
  4. 性能优化:理解网关性能瓶颈和优化策略
  5. 监控运维:学会使用监控工具分析网关性能
相关推荐
SunnyDays10112 分钟前
Java PPT转多种图片格式:打造高质量的文档转换服务
java·ppt转图片·ppt转png·ppt转jpg·ppt转svg·ppt转tiff
David爱编程6 分钟前
多核 CPU 下的缓存一致性问题:隐藏的性能陷阱与解决方案
java·后端
spencer_tseng27 分钟前
Apache Maven 3.1.1 (eclipse luna)
java·maven·apache
2401_831501732 小时前
Linux之Docker虚拟化技术(一)
java·linux·docker
TPBoreas2 小时前
架构设计模式七大原则
java·开发语言
自由的疯2 小时前
Java 实现TXT文件导入功能
java·后端·架构
开开心心就好2 小时前
PDF转长图工具,一键多页转图片
java·服务器·前端·数据库·人工智能·pdf·推荐算法
现在没有牛仔了2 小时前
SpringBoot实现操作日志记录完整指南
java·spring boot·后端
小蒜学长2 小时前
基于django的梧桐山水智慧旅游平台设计与开发(代码+数据库+LW)
java·spring boot·后端·python·django·旅游
浮游本尊2 小时前
Java学习第16天 - 分布式事务与数据一致性
java