Spring AI + Java 17 实战:手把手教你搭建 MCP Server 天气查询服务(附避坑指南) Spring AI Java 17 实战构建高可用MCP天气服务的工程化实践当AI工具链遇上企业级Java生态Spring AI框架正在重新定义大模型应用的开发范式。今天我们将从工程视角拆解如何基于Spring Boot 3.4和JDK 17构建生产级MCP天气服务这个案例不仅能帮助理解AI与业务系统的深度集成更揭示了现代Java开发的技术选型逻辑。1. 环境配置的工程化考量在启动任何Spring AI项目前环境配置往往成为第一个技术决策点。不同于普通Spring Boot应用AI集成项目对版本有着更严苛的要求JDK选择矩阵版本特性JDK 17 LTSJDK 21 LTS非LTS版本模块化支持★★★★☆★★★★★★★★☆☆向量API成熟度★★☆☆☆★★★★☆★★★☆☆Spring AI兼容性★★★★★★★★★☆★★☆☆☆企业部署普及度★★★★★★★★☆☆★☆☆☆☆对于生产环境推荐采用JDK 17的长期支持版本。这个选择平衡了稳定性与新特性支持特别是在容器化部署场景下OpenJDK 17的Docker镜像体积比JDK 21减少约23%。依赖管理的黄金组合properties java.version17/java.version spring-boot.version3.4.4/spring-boot.version spring-ai.version1.0.0-M7/spring-ai.version /properties dependencies !-- WebFlux for reactive streaming -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webflux/artifactId /dependency !-- Actuator for production monitoring -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency /dependencies提示避免直接使用Spring AI的SNAPSHOT版本M7里程碑版已解决早期版本中80%的工具回调内存泄漏问题。2. 天气服务的领域建模实践真正的生产级天气服务不应停留在demo级的简单返回我们需要建立完整的领域模型。以下是经过验证的领域设计模式天气数据实体建模public record WeatherData( ToolParam(description 城市编码) String cityCode, Temperature temperature, Precipitation precipitation, AirQuality airQuality, Wind wind, ToolParam(description 预报时间) LocalDateTime forecastTime ) { public record Temperature(double current, double min, double max, String unit) {} public record Precipitation(double probability, String type, String intensity) {} public record AirQuality(int aqi, String primaryPollutant) {} public record Wind(double speed, int degree, String direction) {} }对应的服务层实现需要处理多种业务场景Service public class AdvancedWeatherService { private final WeatherDataRepository repository; private final ThirdPartyWeatherClient client; Tool(description 获取城市72小时天气预报) public ListWeatherData get72HourForecast( ToolParam(description 城市名称) String cityName, ToolParam(description 温度单位) OptionalString unit) { String normalizedUnit unit.orElse(CELSIUS); return repository.findByCityName(cityName) .orElseGet(() - client.fetchForecast(cityName, normalizedUnit)); } Tool(description 极端天气预警检查) public WeatherAlert checkWeatherAlert( ToolParam(description 地理坐标) String geoCoordinate) { // 实现气象灾害预警逻辑 } }性能优化技巧对高频查询城市实现Caffeine缓存Configuration public class CacheConfig { Bean public CacheManager cacheManager() { CaffeineCacheManager manager new CaffeineCacheManager(); manager.registerCustomCache(weather, Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(30, TimeUnit.MINUTES) .build()); return manager; } }3. MCP服务端的高级配置策略基础配置只能满足开发需求生产环境需要更精细的控制。以下是经过线上验证的配置方案application.yml最佳实践spring: ai: mcp: server: name: weather-mcp-gateway type: ASYNC sse: endpoint: /mcp/events heartbeat-interval: 30s tool: timeout: 5000ms retry: max-attempts: 3 backoff: 1s management: endpoints: web: exposure: include: health,metrics,mcp-tools endpoint: health: show-details: always关键配置说明heartbeat-interval保持SSE连接活跃的心跳间隔tool.timeout工具调用的超时阈值retry配置应对第三方API的瞬时故障安全防护方案Bean public SecurityFilterChain mcpSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher(/mcp/**) .authorizeHttpRequests(auth - auth .requestMatchers(/mcp/events).permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 - oauth2 .jwt(jwt - jwt .decoder(jwtDecoder()) ) ); return http.build(); }4. 客户端集成的工程实践服务端就绪后客户端集成质量直接影响最终用户体验。我们推荐三种主流集成模式1. WebFlux客户端实现public class ReactiveMcpClient { private final WebClient webClient; public MonoWeatherData fetchWeatherReactive(String city) { return webClient.post() .uri(/mcp/tools/execute) .bodyValue(new ToolExecuteRequest(get72HourForecast, Map.of(cityName, city))) .retrieve() .bodyToMono(WeatherData.class) .timeout(Duration.ofSeconds(3)); } }2. 传统Servlet客户端RestController RequestMapping(/api/weather) public class WeatherController { Autowired private McpSyncClient mcpClient; GetMapping(/{city}) public ResponseEntityWeatherData getWeather(PathVariable String city) { CallToolResult result mcpClient.callTool( new CallToolRequest(get72HourForecast, Map.of(cityName, city))); return ResponseEntity.ok(parseResult(result)); } }3. 命令行工具集成#!/bin/bash # weather-cli - 命令行天气查询工具 CITY${1:-北京} curl -X POST http://localhost:8080/mcp/tools/execute \ -H Content-Type: application/json \ -d {tool:get72HourForecast,parameters:{cityName:$CITY}}5. 生产环境避坑指南在实际部署中我们总结了这些血泪经验启动故障排查表现象可能原因解决方案工具注册失败Spring上下文加载顺序问题添加DependsOn(toolRegistry)SSE连接立即断开防火墙拦截WebSocket配置Nginx代理协议升级高并发时工具调用超时线程池耗尽调整WebFlux的worker线程数内存持续增长响应式流未正确释放添加doOnCancel清理逻辑监控指标配置Bean public MeterRegistryCustomizerPrometheusMeterRegistry metricsConfig() { return registry - registry.config().commonTags( application, weather-mcp-service, region, System.getenv(REGION) ); }推荐监控的关键指标spring.ai.mcp.tool.invocations工具调用次数spring.ai.mcp.sse.connections活跃SSE连接数system.cpu.usage容器CPU使用率在Kubernetes环境中建议设置这些资源限制resources: limits: cpu: 2 memory: 1Gi requests: cpu: 500m memory: 512Mi