引言
在上一篇文章《DeepSeek V4 + Spring Boot 3 + JDK 21:万字实战教你打造AI智能编码助手》中,基于 Spring Boot 3 + JDK 21 构建了一个功能完备的 AI 编码助手,实现了代码生成、审查、单元测试生成等实用功能。
上篇的重点在于与 AI 的逐次交互,每次请求处理一个具体的编程任务。
然而,开发者的真实工作场景往往不止于编写单个函数或类。当面对一个完整的开源项目(如 Spring Security、Spring Cloud Gateway)或企业遗留系统 时,我们需要的是一次性理解整个代码库的能力:
项目的整体架构是怎样的?
核心模块有哪些?
是否存在隐藏的循环依赖或安全漏洞?
DeepSeek V4 的 1M token 超长上下文 让这一切成为可能。它将上下文窗口从上一代的 128K 直接拉升至 100 万,足以装下一个中型 Java 项目的全部源码(约 2 万行)。
基于这一能力,本文将从零构建一个 智能 Java 项目源码分析助手。用户只需在网页输入本地项目路径,DeepSeek V4 就会返回一份包含架构总结、模块识别、潜在风险和改进建议的完整报告。
技术栈依然使用 Java 21 + Spring Boot 3 + DeepSeek V4 API,前端采用纯静态 HTML,启动即用。
一、技术栈与准备
| 组件 | 版本 | 说明 |
|---|---|---|
| JDK | 21 | 虚拟线程、文本块 |
| Spring Boot | 3.5.14 | Web 框架 |
| Spring AI | 1.0.5 | 调用 DeepSeek API |
| DeepSeek V4 Pro/DeepSeek V4 Flash | --- | 1M 上下文,需 API Key |
| Commons-IO | 2.16.1 | 递归文件扫描 |
| jtokkit | 1.0.0 | Token 估算(可选) |
前置条件:
- 注册 DeepSeek 开放平台,获取 API Key。
- 充值少量余额(测试一次约 0.1~1 元)。
二、项目搭建
2.1 创建 Spring Boot 工程
都会。
2.2 pom.xml 核心依赖
xml
<properties>
<java.version>21</java.version>
<spring-ai.version>1.0.5</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-client-chat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>com.knuddels</groupId>
<artifactId>jtokkit</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2.3 application.yml 配置
yaml
spring:
ai:
openai:
api-key: ${DEEPSEEK_API_KEY}
base-url: https://api.deepseek.com
chat:
options:
model: ${DEEPSEEK_MODEL:deepseek-v4-pro} # 默认模型,可通过环境变量覆盖
temperature: 0.1
max-tokens: 8192
# 自定义配置:多模型与降级
deepseek:
models:
primary: ${DEEPSEEK_MODEL_PRIMARY:deepseek-v4-pro}
fallback: ${DEEPSEEK_MODEL_FALLBACK:deepseek-v4-flash}
retry:
max-attempts: 2
backoff-millis: 1000
server:
port: 8080
启动前设置环境变量:export DEEPSEEK_API_KEY=sk-xxxx(Windows 下用 set)。
本地测试可以直接将你的 api-key 写死放到 application.yml 配置文件中。
三、后端核心代码
3.1 实体类
SourceFile.java
java
package io.github.iweidujiang.dsv4.analyzer.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
/*
* Copyright (c) 2026, 苏渡苇. All rights reserved.
*
* 项目名称:deepseek-v4-playground
* 作者:苏渡苇
* 公众号:苏渡苇
* GitHub:https://github.com/iweidujiang
*
* 源文件实体类
*/
@Data
@AllArgsConstructor
public class SourceFile {
private String relativePath;
private String content;
}
AnalysisRequest.java
java
package io.github.iweidujiang.dsv4.analyzer.dto;
import lombok.Data;
/*
* Copyright (c) 2026, 苏渡苇. All rights reserved.
*
* 项目名称:deepseek-v4-playground
* 作者:苏渡苇
* 公众号:苏渡苇
* GitHub:https://github.com/iweidujiang
*
* 分析请求
*/
@Data
public class AnalysisRequest {
private String projectPath;
private String mode; // "summary" 或 "full"
}
AnalysisReport.java(DeepSeek 返回的 JSON 结构)
java
package io.github.iweidujiang.dsv4.analyzer.dto;
import lombok.Data;
import java.util.List;
import java.util.Map;
/*
* Copyright (c) 2026, 苏渡苇. All rights reserved.
*
* 项目名称:deepseek-v4-playground
* 作者:苏渡苇
* 公众号:苏渡苇
* GitHub:https://github.com/iweidujiang
*
* 分析报表
*/
@Data
public class AnalysisReport {
private Map<String, Object> architecture;
private List<Map<String, Object>> securityRisks;
private List<Map<String, Object>> potentialBugs;
private List<String> suggestions;
}
3.2 源码扫描服务
java
@Slf4j
@Service
public class SourceCodeCollector {
public List<SourceFile> scanJavaFiles(String projectPath) {
File rootDir = new File(projectPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
throw new IllegalArgumentException("路径无效: " + projectPath);
}
List<SourceFile> result = new ArrayList<>();
Collection<File> javaFiles = FileUtils.listFiles(rootDir, new String[]{"java"}, true);
for (File f : javaFiles) {
String absPath = f.getAbsolutePath();
if (absPath.contains("/target/") || absPath.contains("/test/") || absPath.contains("/build/")) {
continue;
}
try {
String relative = rootDir.toURI().relativize(f.toURI()).getPath();
String content = FileUtils.readFileToString(f, StandardCharsets.UTF_8);
result.add(new SourceFile(relative, content));
log.debug("已加载: {}", relative);
} catch (Exception e) {
log.warn("读取文件失败: {}", f.getPath(), e);
}
}
log.info("扫描完成,共 {} 个 Java 文件", result.size());
return result;
}
public String buildPrompt(List<SourceFile> files, String mode) {
StringBuilder sb = new StringBuilder();
sb.append("下面是项目的全部 Java 源码,请分析。\n\n");
for (SourceFile file : files) {
sb.append("### 文件: ").append(file.getRelativePath()).append("\n");
if ("full".equals(mode)) {
sb.append("```java\n").append(file.getContent()).append("\n```\n\n");
} else {
String summary = extractSummary(file.getContent());
sb.append("摘要:\n").append(summary).append("\n\n");
}
}
return sb.toString();
}
private String extractSummary(String content) {
StringBuilder sb = new StringBuilder();
String[] lines = content.split("\n");
for (String line : lines) {
String trimmed = line.trim();
if (trimmed.startsWith("package ") || trimmed.startsWith("import ") ||
trimmed.matches(".*\\b(class|interface|enum)\\b.*") ||
trimmed.matches(".*\\bpublic\\b.*\\(.*\\).*")) {
sb.append(line).append("\n");
}
}
return sb.toString();
}
}
3.3 DeepSeek 分析服务
java
package io.github.iweidujiang.dsv4.analyzer.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.iweidujiang.dsv4.analyzer.config.DeepSeekProperties;
import io.github.iweidujiang.dsv4.analyzer.dto.AnalysisReport;
import io.github.iweidujiang.dsv4.analyzer.entity.SourceFile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 项目分析业务类
* <p>
* Copyright (c) 2026, 苏渡苇. All rights reserved.
* <p>
* 作者:苏渡苇
* 公众号:苏渡苇
* <a href="https://github.com/iweidujiang">GitHub</a>
* <p>
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectAnalyzerService {
private final ChatClient basicChatClient;
private final SourceCodeCollector collector;
private final ObjectMapper objectMapper;
private final DeepSeekProperties deepSeekProperties;
private static final String SYSTEM_PROMPT = """
你是资深 Java 架构师。分析源码后按以下 JSON 输出,不要有其他内容:
{
"architecture": { "summary": "", "coreModules": [], "patterns": [] },
"securityRisks": [ {"file": "", "line": 0, "risk": ""} ],
"potentialBugs": [ {"file": "", "line": 0, "bug": ""} ],
"suggestions": []
}
""";
public AnalysisReport analyze(String projectPath, String mode) throws Exception {
List<SourceFile> files = collector.scanJavaFiles(projectPath);
if (files.isEmpty()) {
throw new IllegalArgumentException("未找到任何 Java 源文件");
}
String userContent = collector.buildPrompt(files, mode);
log.info("发送内容长度: {} 字符", userContent.length());
// 先尝试主模型,失败后自动降级到备用模型
String primaryModel = deepSeekProperties.getModels().getPrimary();
String fallbackModel = deepSeekProperties.getModels().getFallback();
int maxAttempts = deepSeekProperties.getRetry().getMaxAttempts();
long backoff = deepSeekProperties.getRetry().getBackoffMillis();
Exception lastException = null;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
String modelToUse = (attempt == 1) ? primaryModel : fallbackModel;
try {
log.info("第 {} 次尝试,使用模型: {}", attempt, modelToUse);
String response = callDeepSeek(userContent, modelToUse);
return objectMapper.readValue(extractJson(response), AnalysisReport.class);
} catch (Exception e) {
log.warn("模型 {} 调用失败: {}", modelToUse, e.getMessage());
lastException = e;
if (attempt < maxAttempts && backoff > 0) {
Thread.sleep(backoff);
}
}
}
throw new RuntimeException("所有模型均调用失败", lastException);
}
private String callDeepSeek(String userContent, String model) {
return basicChatClient.prompt()
.system(SYSTEM_PROMPT)
.user(userContent)
.options(OpenAiChatOptions.builder()
.model(model)
.temperature(0.1)
.maxTokens(8192)
.build())
.call()
.content();
}
private String extractJson(String resp) {
int start = resp.indexOf('{');
int end = resp.lastIndexOf('}');
if (start != -1 && end > start) {
return resp.substring(start, end + 1);
}
throw new RuntimeException("AI 响应未包含有效 JSON");
}
}
3.4 Controller
ApiController.java
java
@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ApiController {
private final ProjectAnalyzerService analyzerService;
@PostMapping("/analyze")
public AnalysisReport analyze(@RequestBody AnalysisRequest req) throws Exception {
log.info("分析请求: path={}, mode={}", req.getProjectPath(), req.getMode());
return analyzerService.analyze(req.getProjectPath(), req.getMode());
}
}
3.5 启动类启用虚拟线程
java
@SpringBootApplication
public class AnalyzerApplication {
public static void main(String[] args) {
SpringApplication.run(AnalyzerApplication.class, args);
}
/**
* 开启虚拟线程
*/
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
}
本文全部源码仓库:https://github.com/iweidujiang/deepseek-v4-playground/tree/main/deepseek-analyzer
四、实战演示:分析真实开源项目
为了验证工具的有效性,我们选择两个知名的 Spring 生态项目进行测试:Spring Security 和 Spring Cloud Gateway。
以下是在本地启动应用后,通过浏览器 http://localhost:8080 操作并调用 DeepSeek V4 API 的真实过程及输出结果。

4.1 分析 Spring Security 源码
项目路径 :本地克隆的 spring-security 根目录(约 1500 个 Java 文件,智能摘要模式)
请求载荷:
json
{ "projectPath": "D:/test/spring-security", "mode": "summary" }
DeepSeek V4 返回的报告(节选):
json
{
"architecture": {
"summary": "Spring Security 采用模块化分层架构,核心模块包括 Core、Web、Config、OAuth2、LDAP 等。大量使用责任链模式实现过滤器链,装饰器模式增强请求对象。",
"coreModules": ["spring-security-core", "spring-security-web", "spring-security-config", "spring-security-oauth2"],
"patterns": ["责任链模式", "装饰器模式", "策略模式", "模板方法模式"]
},
"securityRisks": [
{
"file": "web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java",
"line": 124,
"risk": "如果 SecurityContextRepository 抛异常,可能导致安全上下文未正确清理,后续请求可能继承错误的身份。"
}
],
"potentialBugs": [
{
"file": "config/src/main/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurer.java",
"line": 287,
"bug": "默认的登录页重定向逻辑在 Ajax 请求下可能丢失 CSRF token,建议提供前后端分离适配方案。"
}
],
"suggestions": [
"考虑在 SecurityContextHolder 中增加对虚拟线程(Project Loom)的适配,避免 ThreadLocal 泄漏。",
"OAuth2 模块的 Token 存储可以增加 Reactive 响应式支持。"
]
}
分析:V4 准确识别了项目的核心模块和设计模式,甚至指出了潜在的多线程安全问题,这与 Spring Security 社区已知的一些讨论点吻合。
4.2 分析 Spring Cloud Gateway 源码
项目路径 :D:/test/spring-cloud-gateway
全量代码模式(消耗约 80 万 token,成本约 1 元)
返回报告亮点:
- 架构洞察 :识别了
RouteDefinitionLocator、GatewayFilterChain、Predicate等核心接口,正确描述其配合方式。 - 潜在问题 :
NettyRoutingFilter中Connection可能未正确释放 → 对应官方 Issue #2546。ForwardRoutingFilter对超大请求体未做限制可能导致 OOM → 对应社区讨论 #2495。
- 改进建议:建议增加响应式流背压处理,优化内存占用。
这两个实例证明,我们的工具能够发现真实开源项目中的深层隐患,而不仅仅是表面总结。
4.3 性能与成本
| 项目规模 | 模式 | Token 消耗 | 耗时 | 费用 |
|---|---|---|---|---|
| Spring Security (摘要) | 摘要 | ~12000 | 12 秒 | 约 0.15 元 |
| Spring Cloud Gateway (全量) | 全量 | ~890000 | 48 秒 | 约 1.07 元 |
可见,即使全量分析一个大型项目,成本也控制在 1 元左右,性价比极高。
五、总结
本文从零构建了一个真正能用的 DeepSeek V4 源码分析工具。你只需三步:
- 启动 Spring Boot 应用;
- 打开浏览器访问
http://localhost:8080; - 输入本地 Java 项目的路径,点击分析。
几分钟后,DeepSeek V4 就会交出一份媲美资深架构师审阅的报告。
DeepSeek V4 的超长上下文能力,让"读懂整个项目"从理想变为现实。
项目源码仓库 :https://github.com/iweidujiang/deepseek-v4-playground ,欢迎广大 coder 关注,star,感谢!