OpenRewrite 实战指南

从 Spring 微服务萃取代码知识:OpenRewrite 实战指南

一、背景

在企业微服务系统中,如果有 150+ 个 Spring / Spring Boot / Spring Cloud 微服务,仅仅把代码丢进向量数据库做 RAG,实际上很难真正解决:

  • 某个 Service 有哪些 API?

  • 一个 API 最终调用了哪些 Service?

  • 哪些服务依赖某个服务?

  • 某个数据库表被哪些服务使用?

  • 哪个 Kafka Topic 有哪些生产者和消费者?

  • 某个 Java 方法被哪些地方调用?

  • 修改一个接口会影响哪些服务?

  • 一个业务流程到底经过哪些 Controller、Service、Repository?

  • 哪些微服务之间存在 Feign 调用?

  • 哪些服务使用 Redis?

  • 哪些代码属于 Spring Cloud?

  • 某个类、方法、接口在哪个 Git Commit 中发生了变化?

如果这些信息完全依赖 LLM 从源代码中"读出来",成本高、速度慢,而且结果不稳定。

因此更合理的方案是:

让 OpenRewrite / AST / Static Analysis 负责产生事实,让 LLM 负责理解事实。

也就是:

复制代码
                    ┌─────────────────────┐
                    │   Git Repository    │
                    │  150+ Microservices │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │   Code Scanner      │
                    │                     │
                    │ OpenRewrite         │
                    │ Maven / Gradle      │
                    │ Git                 │
                    │ SQL Parser          │
                    └──────────┬──────────┘
                               │
                               ▼
                 ┌───────────────────────────┐
                 │ Structural Knowledge      │
                 │                           │
                 │ Service                   │
                 │ Package                   │
                 │ Class                     │
                 │ Method                    │
                 │ API                       │
                 │ Call                      │
                 │ Feign                     │
                 │ DB                        │
                 │ Kafka                     │
                 │ Redis                     │
                 │ Dependency                │
                 └────────────┬──────────────┘
                              │
                ┌─────────────┴─────────────┐
                ▼                           ▼
       PostgreSQL / pgvector              Neo4j
       文档 / RAG                         Knowledge Graph
                │                           │
                └─────────────┬─────────────┘
                              ▼
                         LLM / Agent
                              │
                ┌─────────────┼─────────────┐
                ▼             ▼             ▼
             架构分析       影响分析       文档生成
             业务流程       依赖分析       Code Agent

二、最终要达到什么效果?

最终希望把一个 Spring 微服务:

复制代码
order-service

转换成机器可以理解的数据:

复制代码
Service
 ├── Package
 │    ├── Class
 │    │    ├── Field
 │    │    └── Method
 │    │         ├── Annotation
 │    │         ├── Method Call
 │    │         ├── SQL
 │    │         └── API
 │    │
 │    └── ...
 │
 ├── REST API
 │
 ├── Feign Client
 │
 ├── Database
 │
 ├── Kafka
 │
 ├── Redis
 │
 └── Dependencies

例如:

复制代码
POST /orders
       │
       ▼
OrderController.createOrder()
       │
       ▼
OrderService.createOrder()
       │
       ├──────────────► UserClient.getUser()
       │                       │
       │                       ▼
       │                 user-service
       │
       ├──────────────► InventoryClient.reserve()
       │                       │
       │                       ▼
       │                 inventory-service
       │
       ▼
OrderRepository.save()
       │
       ▼
orders table
       │
       ▼
Kafka: order-created
       │
       ├────────────► payment-service
       │
       └────────────► notification-service

这才是真正可以供 Agent 使用的"代码知识"。


三、第一阶段:准备开发环境

3.1 推荐环境

如果你的代码主要是 Java / Spring,我建议:

软件 推荐
OS Windows / Linux
JDK Java 21
Maven 3.9.x
Git 2.x
IDE IntelliJ IDEA
OpenRewrite 当前稳定版本
PostgreSQL 16+
pgvector 最新稳定版
Neo4j 5.x
Python 3.11+,用于辅助处理 JSON
Node.js 可选
Docker 推荐用于 PostgreSQL / Neo4j

OpenRewrite 当前 Recipe 开发环境要求 JDK 21;官方也推荐 IntelliJ IDEA 2024.1+。


四、Windows 环境安装

如果你是在 Windows 上开发,可以使用 PowerShell。

4.1 检查 Java

复制代码
java -version

应该看到:

复制代码
java version "21.x.x"

如果没有:

复制代码
$env:JAVA_HOME

检查 JAVA_HOME。

例如:

复制代码
C:\Program Files\Java\jdk-21

设置:

复制代码
setx JAVA_HOME "C:\Program Files\Java\jdk-21"

重新打开 PowerShell。


五、检查 Maven

复制代码
mvn -version

例如:

复制代码
Apache Maven 3.9.x
Java version: 21

如果你的项目本身已经使用 Maven Wrapper:

复制代码
.\mvnw.cmd -version

优先使用项目自己的 Maven Wrapper。


六、检查 Git

复制代码
git --version

例如:

复制代码
git version 2.x

七、Linux 环境

Ubuntu 示例:

复制代码
sudo apt update

sudo apt install -y git curl unzip

安装 JDK:

复制代码
sudo apt install -y openjdk-21-jdk

检查:

复制代码
java -version

然后:

复制代码
mvn -version

八、第一件事:不要直接处理 150 个服务

强烈建议:

先选择一个典型 Spring Boot 微服务做 POC。

例如:

复制代码
order-service

最好这个服务同时包含:

  • Controller

  • Service

  • Repository

  • Feign

  • Kafka

  • MyBatis/JPA

  • Redis

  • Maven

  • Spring Boot

这样可以一次性验证整个知识模型。


九、建立代码知识扫描项目

不要把 Scanner 放进业务微服务。

单独建立:

复制代码
code-knowledge-scanner

建议最终目录:

复制代码
code-knowledge-scanner
│
├── pom.xml
│
├── src
│   ├── main
│   │   └── java
│   │       └── com.company.knowledge
│   │           ├── recipe
│   │           │   ├── ClassScanner.java
│   │           │   ├── MethodScanner.java
│   │           │   ├── AnnotationScanner.java
│   │           │   ├── RestApiScanner.java
│   │           │   ├── FeignScanner.java
│   │           │   ├── MethodCallScanner.java
│   │           │   ├── KafkaScanner.java
│   │           │   └── DatabaseScanner.java
│   │           │
│   │           ├── model
│   │           │   ├── ServiceInfo.java
│   │           │   ├── ClassInfo.java
│   │           │   ├── MethodInfo.java
│   │           │   ├── ApiInfo.java
│   │           │   ├── DependencyInfo.java
│   │           │   └── KnowledgeGraph.java
│   │           │
│   │           └── Main.java
│   │
│   └── test
│
├── rewrite.yml
│
└── output

十、创建项目

最简单的方法:

复制代码
mkdir code-knowledge-scanner

cd code-knowledge-scanner

使用 Maven:

复制代码
mvn -B archetype:generate \
  -DgroupId=com.company.knowledge \
  -DartifactId=code-knowledge-scanner \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.5

OpenRewrite 官方也提供 Recipe Starter,可以直接作为 Recipe 项目的起点。


十一、理解 OpenRewrite 的三个核心概念

真正开始写 Scanner 前,需要理解:

复制代码
Source Code
     │
     ▼
Parser
     │
     ▼
LST
     │
     ▼
Visitor
     │
     ▼
Recipe
     │
     ▼
Knowledge

其中:

LST

OpenRewrite 使用 Lossless Semantic Tree 保存代码结构。

例如:

复制代码
@Service
public class OrderService {

    public Order createOrder(User user) {
        return repository.save(new Order());
    }
}

OpenRewrite 可以识别:

复制代码
ClassDeclaration
 ├── Annotation
 │     └── @Service
 │
 ├── MethodDeclaration
 │     ├── name=createOrder
 │     ├── parameter=User
 │     └── return=Order
 │
 └── MethodInvocation
       └── repository.save()

十二、Visitor

Visitor 是真正遍历代码的地方。

例如:

复制代码
visitCompilationUnit()
        │
        ├── package
        ├── imports
        ├── classes
        │     ├── fields
        │     └── methods
        │
        └── comments

OpenRewrite 官方文档明确说明 Visitor 是 Recipe 中执行核心逻辑的地方。


十三、Recipe

Recipe 是一个分析或者转换任务。

例如:

复制代码
ClassScannerRecipe
MethodScannerRecipe
RestApiScannerRecipe
FeignScannerRecipe

Recipe 调用 Visitor:

复制代码
Recipe
   │
   ▼
Visitor
   │
   ▼
LST
   │
   ▼
Knowledge

OpenRewrite 官方把 Recipe 定义为一组针对 LST 的搜索或重构操作。


十四、第一个任务:萃取 Class

第一步不要做 API。

只做:

复制代码
Class
Package
Superclass
Interface
Annotation
Field
Method

目标:

复制代码
{
  "className": "OrderService",
  "fullyQualifiedName": "com.company.order.service.OrderService",
  "packageName": "com.company.order.service",
  "annotations": [
    "org.springframework.stereotype.Service"
  ],
  "superClass": null,
  "interfaces": [],
  "file": "src/main/java/com/company/order/service/OrderService.java"
}

十五、ClassInfo 数据模型

建议统一定义:

复制代码
{
  "id": "class:com.company.order.service.OrderService",
  "serviceId": "order-service",
  "type": "CLASS",
  "name": "OrderService",
  "fullyQualifiedName": "com.company.order.service.OrderService",
  "packageName": "com.company.order.service",
  "filePath": "src/main/java/com/company/order/service/OrderService.java",
  "lineStart": 10,
  "lineEnd": 120,
  "annotations": [
    {
      "name": "org.springframework.stereotype.Service"
    }
  ],
  "interfaces": [],
  "superClass": null
}

注意:

不要只保存简单 JSON。

必须保存:

复制代码
serviceId
repository
branch
commit
filePath
line
hash
scanTime

因为未来需要做增量扫描和版本比较。


十六、第二个任务:Method

然后萃取:

复制代码
Method

例如:

复制代码
public Order createOrder(
        Long userId,
        CreateOrderRequest request)

保存:

复制代码
{
  "id": "method:com.company.order.service.OrderService#createOrder",
  "classId": "class:com.company.order.service.OrderService",
  "name": "createOrder",
  "signature": "createOrder(Long, CreateOrderRequest)",
  "returnType": "com.company.order.domain.Order",
  "parameters": [
    {
      "name": "userId",
      "type": "java.lang.Long"
    },
    {
      "name": "request",
      "type": "com.company.order.dto.CreateOrderRequest"
    }
  ],
  "annotations": [],
  "visibility": "public"
}

十七、第三个任务:Annotation

这是 Spring 项目非常关键的一步。

至少识别:

复制代码
@RestController
@Controller
@Service
@Repository
@Component
@Configuration
@Bean
@Autowired
@Resource
@Transactional
@Async
@Scheduled
@Cacheable
@KafkaListener
@FeignClient

还需要识别:

复制代码
@RequestMapping
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

以及:

复制代码
@Entity
@Table
@Id
@Column

十八、第四个任务:REST API

例如:

复制代码
@RestController
@RequestMapping("/orders")
public class OrderController {

    @PostMapping
    public Order create(@RequestBody CreateOrderRequest request) {
        return orderService.create(request);
    }
}

转换成:

复制代码
{
  "id": "api:order-service:POST:/orders",
  "serviceId": "order-service",
  "controllerClass": "com.company.order.controller.OrderController",
  "method": "create",
  "httpMethod": "POST",
  "path": "/orders",
  "requestType": "CreateOrderRequest",
  "responseType": "Order"
}

十九、REST API 最重要的关系

不要只保存 API。

要建立:

复制代码
API
 │
 ▼
Controller Method
 │
 ▼
Service Method
 │
 ▼
Repository Method
 │
 ▼
Database

例如:

复制代码
{
  "from": "api:order-service:POST:/orders",
  "relation": "CALLS",
  "to": "method:OrderController#create"
}

然后:

复制代码
{
  "from": "method:OrderController#create",
  "relation": "CALLS",
  "to": "method:OrderService#create"
}

二十、第五个任务:Method Call

这是整个系统非常重要的一步。

例如:

复制代码
public Order createOrder() {

    User user = userService.getUser();

    inventoryService.reserve();

    return orderRepository.save(order);
}

要生成:

复制代码
[
  {
    "caller": "OrderService#createOrder",
    "callee": "UserService#getUser"
  },
  {
    "caller": "OrderService#createOrder",
    "callee": "InventoryService#reserve"
  },
  {
    "caller": "OrderService#createOrder",
    "callee": "OrderRepository#save"
  }
]

二十一、为什么必须做 Type Attribution?

假设:

复制代码
logger.info("hello");

单纯字符串扫描只能知道:

复制代码
logger.info

但是 OpenRewrite Type Attribution 可以进一步判断:

复制代码
logger
 ↓
org.slf4j.Logger
 ↓
info(String)

这对于准确建立 Method Call Graph 非常重要。OpenRewrite 官方文档明确说明 Type Attribution 能够提供类型解析、方法绑定、继承关系等信息。

所以:

不要使用正则表达式作为 Java 方法调用分析的主方案。

正则可以做辅助搜索,但不能作为最终知识来源。


二十二、第六个任务:Feign

Spring Cloud 系统里面非常重要。

例如:

复制代码
@FeignClient(name = "user-service")
public interface UserClient {

    @GetMapping("/users/{id}")
    User getUser(@PathVariable Long id);
}

生成:

复制代码
{
  "id": "feign:order-service:UserClient",
  "sourceService": "order-service",
  "clientClass": "com.company.order.client.UserClient",
  "targetService": "user-service",
  "methods": [
    {
      "name": "getUser",
      "httpMethod": "GET",
      "path": "/users/{id}",
      "returnType": "User"
    }
  ]
}

进一步生成:

复制代码
{
  "from": "service:order-service",
  "relation": "CALLS",
  "to": "service:user-service",
  "via": "FEIGN",
  "client": "UserClient"
}

这样就可以建立:

复制代码
order-service
       │
       │ FEIGN
       ▼
user-service

二十三、第七个任务:Repository

识别:

复制代码
@Repository
JpaRepository
CrudRepository
MongoRepository
@Mapper
MyBatis Mapper

例如:

复制代码
@Repository
public interface OrderRepository
        extends JpaRepository<Order, Long> {
}

生成:

复制代码
{
  "id": "repository:OrderRepository",
  "className": "OrderRepository",
  "type": "JPA",
  "entity": "Order",
  "baseRepository": "JpaRepository"
}

二十四、第八个任务:MyBatis SQL

例如:

复制代码
@Select("""
    select *
    from orders
    where user_id = #{userId}
""")
Order findByUserId(Long userId);

不要只保存 SQL。

应该保存:

复制代码
{
  "id": "sql:OrderMapper#findByUserId",
  "mapper": "OrderMapper",
  "method": "findByUserId",
  "operation": "SELECT",
  "tables": [
    "orders"
  ],
  "columns": [
    "user_id"
  ],
  "sql": "select * from orders where user_id = #{userId}"
}

然后建立:

复制代码
OrderService#createOrder
        │
        ▼
OrderMapper#findByUserId
        │
        ▼
orders

二十五、第九个任务:JPA

如果使用:

复制代码
@Entity
@Table(name = "orders")
public class Order {
}

生成:

复制代码
{
  "entity": "Order",
  "table": "orders",
  "schema": null,
  "fields": [
    {
      "name": "id",
      "column": "id",
      "type": "Long"
    },
    {
      "name": "userId",
      "column": "user_id",
      "type": "Long"
    }
  ]
}

最终:

复制代码
Order
  │
  ▼
orders

二十六、第十个任务:Kafka

例如:

复制代码
@KafkaListener(topics = "order-created")
public void handle(OrderCreatedEvent event) {
}

生成:

复制代码
{
  "id": "kafka-consumer:order-service:OrderConsumer#handle",
  "serviceId": "order-service",
  "type": "CONSUMER",
  "topic": "order-created",
  "method": "OrderConsumer#handle"
}

生产:

复制代码
kafkaTemplate.send("order-created", event);

生成:

复制代码
{
  "serviceId": "order-service",
  "type": "PRODUCER",
  "topic": "order-created",
  "method": "OrderService#createOrder"
}

然后建立:

复制代码
order-service
      │
      │ PRODUCES
      ▼
order-created
      │
      │ CONSUMES
      ▼
payment-service

二十七、第十一个任务:Redis

Spring 项目中可以识别:

复制代码
RedisTemplate
StringRedisTemplate
@Cacheable
@CachePut
@CacheEvict

例如:

复制代码
@Cacheable(value = "users", key = "#id")
public User getUser(Long id) {
}

生成:

复制代码
{
  "type": "CACHE",
  "serviceId": "user-service",
  "method": "UserService#getUser",
  "cacheName": "users",
  "keyExpression": "#id"
}

二十八、第十二个任务:Maven Dependency

读取:

复制代码
pom.xml

生成:

复制代码
{
  "groupId": "org.springframework.boot",
  "artifactId": "spring-boot-starter-web",
  "version": "3.x",
  "scope": "compile"
}

最终可以得到:

复制代码
order-service
 │
 ├── spring-boot
 ├── spring-cloud
 ├── openfeign
 ├── kafka
 ├── redis
 └── postgresql

二十九、OpenRewrite 本身如何运行?

如果你只是验证 OpenRewrite 是否正常工作,可以在一个业务项目里配置 Maven Plugin。

官方 Maven Plugin 支持:

复制代码
mvn rewrite:run

以及:

复制代码
mvn rewrite:dryRun

run 会实际修改代码,dryRun 不修改代码并生成 diff。

例如:

复制代码
mvn rewrite:dryRun

然后:

复制代码
git diff

查看结果。


三十、建议先验证 OpenRewrite

业务项目:

复制代码
order-service

进入:

复制代码
cd order-service

运行:

复制代码
mvn rewrite:discover

这个命令可以发现当前 classpath 上可用的 Recipe。官方 Maven Plugin 提供了该 goal。

然后测试:

复制代码
mvn rewrite:dryRun

最后:

复制代码
mvn rewrite:run

但是:

我们的最终目标不是修改代码,而是利用 OpenRewrite 读取代码并生成 Knowledge。

所以生产环境不要把"代码重构 Recipe"和"知识萃取 Recipe"混在一起。


三十一、推荐建立两个项目

最终建议:

复制代码
openrewrite-code-knowledge

和:

复制代码
openrewrite-code-migration

分别负责:

复制代码
code-knowledge
    ↓
只读分析

和:

复制代码
code-migration
    ↓
代码修改

这是非常重要的架构隔离。


三十二、推荐的 Scanner 模块

最终:

复制代码
code-knowledge-scanner
│
├── parser
│   ├── JavaParser
│   ├── MavenParser
│   └── GradleParser
│
├── scanner
│   ├── ServiceScanner
│   ├── PackageScanner
│   ├── ClassScanner
│   ├── MethodScanner
│   ├── AnnotationScanner
│   ├── ApiScanner
│   ├── MethodCallScanner
│   ├── FeignScanner
│   ├── RepositoryScanner
│   ├── DatabaseScanner
│   ├── KafkaScanner
│   ├── RedisScanner
│   └── DependencyScanner
│
├── model
│
├── graph
│
├── output
│
└── cli

三十三、统一 Knowledge Model

不要让每个 Scanner 自己定义 JSON。

统一模型:

复制代码
Knowledge
├── Repository
├── Service
├── Package
├── Class
├── Method
├── Field
├── Annotation
├── API
├── Dependency
├── MethodCall
├── Feign
├── Database
├── SQL
├── Kafka
├── Redis
└── Event

三十四、Service 数据格式

复制代码
{
  "id": "service:order-service",
  "name": "order-service",
  "repository": "git@company/order-service.git",
  "branch": "main",
  "commit": "8a91c2f",
  "language": "JAVA",
  "framework": [
    "SPRING_BOOT",
    "SPRING_CLOUD"
  ],
  "build": "MAVEN",
  "version": "1.0.0",
  "scanTime": "2026-09-04T10:00:00Z"
}

三十五、Class 数据格式

复制代码
{
  "id": "class:com.company.order.OrderService",
  "serviceId": "service:order-service",
  "name": "OrderService",
  "fullyQualifiedName": "com.company.order.OrderService",
  "packageName": "com.company.order",
  "filePath": "src/main/java/com/company/order/OrderService.java",
  "lineStart": 20,
  "lineEnd": 150,
  "annotations": [
    "org.springframework.stereotype.Service"
  ]
}

三十六、Method 数据格式

复制代码
{
  "id": "method:com.company.order.OrderService#createOrder",
  "classId": "class:com.company.order.OrderService",
  "name": "createOrder",
  "signature": "createOrder(CreateOrderRequest)",
  "returnType": "Order",
  "visibility": "public",
  "annotations": [
    "org.springframework.transaction.annotation.Transactional"
  ]
}

三十七、API 数据格式

复制代码
{
  "id": "api:order-service:POST:/orders",
  "serviceId": "service:order-service",
  "httpMethod": "POST",
  "path": "/orders",
  "controller": "OrderController",
  "method": "createOrder",
  "requestType": "CreateOrderRequest",
  "responseType": "Order"
}

三十八、关系数据格式

这是整个系统最重要的数据。

推荐统一:

复制代码
{
  "source": "method:OrderService#createOrder",
  "relation": "CALLS",
  "target": "method:UserService#getUser",
  "confidence": 1.0
}

例如:

复制代码
{
  "source": "service:order-service",
  "relation": "DEPENDS_ON",
  "target": "service:user-service",
  "via": "FEIGN"
}

Kafka:

复制代码
{
  "source": "service:order-service",
  "relation": "PRODUCES",
  "target": "kafka:order-created"
}

数据库:

复制代码
{
  "source": "method:OrderMapper#findByUserId",
  "relation": "READS",
  "target": "table:orders"
}

三十九、为什么一定要保存 Graph?

因为你的系统最终不是简单的:

复制代码
Document → Vector

而是:

复制代码
Node + Relation

例如:

复制代码
                 ┌─────────────┐
                 │order-service│
                 └──────┬──────┘
                        │
             ┌──────────┼──────────┐
             ▼          ▼          ▼
        user-service inventory   payment
             │          │          │
             ▼          ▼          ▼
           users      inventory   payment

这就是 Knowledge Graph。


四十、推荐 PostgreSQL + Neo4j

第一阶段可以:

复制代码
PostgreSQL

保存全部事实数据。

例如:

复制代码
services
classes
methods
apis
dependencies
method_calls
databases
kafka_topics

如果以后关系查询复杂,再加入:

复制代码
Neo4j

例如查询:

order-service 到 payment-service 中间经过了哪些调用?

Graph DB 非常适合。


四十一、PostgreSQL 表设计

services

复制代码
CREATE TABLE services (
    id              VARCHAR(200) PRIMARY KEY,
    name            VARCHAR(200),
    repository      TEXT,
    branch          VARCHAR(200),
    commit_hash     VARCHAR(100),
    language        VARCHAR(50),
    frameworks      JSONB,
    scan_time       TIMESTAMP
);

classes

复制代码
CREATE TABLE classes (
    id              VARCHAR(500) PRIMARY KEY,
    service_id      VARCHAR(200),
    name            VARCHAR(500),
    fqcn            VARCHAR(1000),
    package_name    VARCHAR(1000),
    file_path       TEXT,
    line_start      INT,
    line_end        INT,
    annotations     JSONB
);

methods

复制代码
CREATE TABLE methods (
    id              VARCHAR(1000) PRIMARY KEY,
    class_id        VARCHAR(500),
    name            VARCHAR(500),
    signature       TEXT,
    return_type     VARCHAR(1000),
    parameters      JSONB,
    annotations     JSONB
);

relations

复制代码
CREATE TABLE relations (
    source_id       VARCHAR(1000),
    relation_type   VARCHAR(100),
    target_id       VARCHAR(1000),
    metadata        JSONB,
    PRIMARY KEY (
        source_id,
        relation_type,
        target_id
    )
);

四十二、最终 JSON 文件目录

每个微服务建议生成:

复制代码
output/
└── order-service/
    └── 8a91c2f/
        ├── service.json
        ├── packages.json
        ├── classes.json
        ├── methods.json
        ├── fields.json
        ├── annotations.json
        ├── apis.json
        ├── dependencies.json
        ├── method-calls.json
        ├── feign.json
        ├── database.json
        ├── sql.json
        ├── kafka.json
        ├── redis.json
        ├── relations.json
        └── summary.json

这里:

复制代码
8a91c2f

就是 Git Commit。

这一步非常重要。


四十三、为什么必须绑定 Git Commit?

假设:

复制代码
2026-08-01
OrderService#createOrder()

调用:

复制代码
UserService#getUser()

到了:

复制代码
2026-09-01

可能已经变成:

复制代码
CustomerService#getCustomer()

如果没有版本:

复制代码
Agent

不知道哪个关系是当前的。

所以:

复制代码
Knowledge Version
=
Repository
+
Branch
+
Commit
+
File Hash

四十四、增量扫描

150 个服务如果每次都全量扫描:

复制代码
150 × 全部 Java 文件

成本没有必要。

使用:

复制代码
git diff

找到变化文件。

例如:

复制代码
git diff --name-only HEAD~1 HEAD

得到:

复制代码
src/main/java/OrderService.java
src/main/java/OrderController.java

只扫描这些文件。


四十五、但是有一个重要问题

如果:

复制代码
A.java

调用:

复制代码
B.java

现在 B.java 修改了。

那么:

复制代码
A.java

可能没有修改,但是:

复制代码
A → B

的语义可能发生变化。

所以生产级增量分析应该:

复制代码
Git Diff
   │
   ▼
Changed Files
   │
   ▼
Changed Symbols
   │
   ▼
Affected Callers
   │
   ▼
Recalculate Graph

第一版可以先做:

复制代码
文件级增量

第二版再做:

复制代码
Symbol-level incremental analysis

四十六、第一阶段不要做 LLM

这是整个项目最重要的实施原则之一。

第一阶段:

复制代码
Java
 ↓
OpenRewrite
 ↓
JSON

不要:

复制代码
Java
 ↓
LLM
 ↓
JSON

因为你需要首先建立:

Ground Truth

也就是:

复制代码
事实层

四十七、什么时候加入 LLM?

等:

复制代码
Class
Method
API
Call
Feign
DB
Kafka
Redis
Dependency

全部结构化之后,再加入 LLM。

例如:

复制代码
OrderController#create
        │
        ├── OrderService#create
        ├── UserClient#getUser
        ├── InventoryClient#reserve
        ├── OrderRepository#save
        └── Kafka order-created

把这些结构化信息交给 LLM:

复制代码
请分析这个 API 的业务流程。

LLM 才需要回答:

复制代码
该接口用于创建订单。

主要流程:

1. 查询用户信息
2. 检查库存
3. 创建订单
4. 保存订单
5. 发布 order-created 事件

涉及:
- user-service
- inventory-service
- order database
- Kafka

这时候 LLM 的 Token 消耗会大幅降低。


四十八、最终 Agent 架构

最终可以做成:

复制代码
                    Code Knowledge Platform
                             │
          ┌──────────────────┼──────────────────┐
          ▼                  ▼                  ▼
      Static Facts       Knowledge Graph       Vector
          │                  │                  │
          └──────────────────┼──────────────────┘
                             ▼
                         Agent Layer
                             │
          ┌──────────────────┼──────────────────┐
          ▼                  ▼                  ▼
    Architecture Agent   Impact Agent       Business Agent
          │                  │                  │
          ▼                  ▼                  ▼
      架构分析             影响分析           流程分析

四十九、Agent 可以回答什么?

例如:

问题 1

复制代码
order-service 依赖哪些服务?

直接查询 Graph:

复制代码
user-service
inventory-service
payment-service

不需要 LLM。


问题 2

复制代码
POST /orders 会访问哪些数据库?

Graph:

复制代码
POST /orders
    ↓
OrderController#create
    ↓
OrderService#create
    ↓
OrderRepository#save
    ↓
orders

问题 3

复制代码
修改 Order 表会影响哪些服务?

Graph:

复制代码
orders
 │
 ├── order-service
 ├── reporting-service
 ├── payment-service
 └── settlement-service

问题 4

复制代码
解释创建订单业务流程

这时候再调用 LLM。


五十、第一版必须实现哪些 Scanner?

我建议按照下面顺序:

POC-1

复制代码
Class
Method
Annotation

目标:

复制代码
Java → JSON

POC-2

增加:

复制代码
Spring
REST API
Method Call

目标:

复制代码
Controller
 ↓
Service
 ↓
Method

POC-3

增加:

复制代码
Feign
Maven
Repository
JPA
MyBatis
SQL

目标:

复制代码
Service → Service
Service → DB

POC-4

增加:

复制代码
Kafka
Redis
RabbitMQ

目标:

复制代码
Event Graph

POC-5

增加:

复制代码
PostgreSQL
Neo4j

目标:

复制代码
Knowledge Graph

POC-6

增加:

复制代码
LLM
RAG
Agent

目标:

复制代码
Software Intelligence Agent

五十一、150+ 微服务生产架构

最终建议:

复制代码
                    GitLab / GitHub
                           │
                           ▼
                  Repository Manager
                           │
                           ▼
                 ┌─────────────────┐
                 │ Scanner Manager  │
                 └────────┬────────┘
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
         Scanner 1    Scanner 2    Scanner N
         service A    service B    service N
             │            │            │
             └────────────┼────────────┘
                          ▼
                OpenRewrite Engine
                          │
                          ▼
                  Knowledge JSON
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
        PostgreSQL       Neo4j       Object Storage
             │            │
             └────────────┼────────────┘
                          ▼
                    Semantic Layer
                          │
                          ▼
                         LLM
                          │
                          ▼
                  Agent / RAG / MCP

五十二、推荐 CLI

最终不要让用户直接操作 Java 类。

做成:

复制代码
code-knowledge scan

例如:

复制代码
code-knowledge scan \
  --repo /workspace/order-service \
  --output /output/order-service

指定 Commit:

复制代码
code-knowledge scan \
  --repo /workspace/order-service \
  --commit 8a91c2f \
  --output /output/order-service/8a91c2f

增量:

复制代码
code-knowledge scan \
  --repo /workspace/order-service \
  --from HEAD~1 \
  --to HEAD

五十三、最终 CLI

建议设计成:

复制代码
code-knowledge
│
├── scan
├── scan-all
├── diff
├── export
├── import
├── graph
├── search
└── version

例如:

复制代码
code-knowledge scan-all \
  --repos ./repos \
  --output ./knowledge

150 个服务全部扫描。


五十四、一个完整执行流程

实际项目建议严格按照下面顺序执行。

Step 1

安装:

复制代码
JDK 21
Maven
Git
IntelliJ
Docker

Step 2

创建:

复制代码
code-knowledge-scanner

Step 3

验证 OpenRewrite:

复制代码
mvn rewrite:discover

Step 4

选择一个:

复制代码
order-service

Step 5

执行:

复制代码
ClassScanner

输出:

复制代码
classes.json

Step 6

执行:

复制代码
MethodScanner

输出:

复制代码
methods.json

Step 7

执行:

复制代码
AnnotationScanner

输出:

复制代码
annotations.json

Step 8

执行:

复制代码
RestApiScanner

输出:

复制代码
apis.json

Step 9

执行:

复制代码
MethodCallScanner

输出:

复制代码
method-calls.json

Step 10

执行:

复制代码
FeignScanner

输出:

复制代码
feign.json

Step 11

执行:

复制代码
DatabaseScanner

输出:

复制代码
database.json
sql.json

Step 12

执行:

复制代码
KafkaScanner

输出:

复制代码
kafka.json

Step 13

执行:

复制代码
RedisScanner

输出:

复制代码
redis.json

Step 14

合并:

复制代码
relations.json

形成:

复制代码
Service
Class
Method
API
DB
Kafka
Service Dependency
Method Call

完整知识图谱。


五十五、第一阶段验收标准

不要以:

复制代码
"Scanner 可以运行"

作为验收标准。

应该定义:

Class

复制代码
95%+

Method

复制代码
95%+

Spring Annotation

复制代码
95%+

REST API

复制代码
95%+

Feign

复制代码
90%+

DB

复制代码
80%+

Kafka

复制代码
90%+

五十六、特别需要注意:静态调用图不是运行时调用图

例如:

复制代码
if (condition) {
    serviceA.call();
} else {
    serviceB.call();
}

静态分析只能知道:

复制代码
A → serviceA
A → serviceB

不能确定运行时到底执行哪一个。

所以最好定义:

复制代码
STATIC

和:

复制代码
RUNTIME

两个来源。

最终:

复制代码
Static Call Graph
        +
Runtime Trace
        ↓
Actual Call Graph

未来可以接:

复制代码
OpenTelemetry
SkyWalking
Jaeger
Zipkin

这样会更准确。


五十七、不要把所有源码直接放进 RAG

这是另一个非常重要的设计原则。

错误:

复制代码
Java Source
   ↓
Embedding
   ↓
Vector DB

推荐:

复制代码
Java Source
   ↓
OpenRewrite
   ↓
Structured Facts
   ↓
Graph
   ↓
LLM Summary
   ↓
RAG

RAG 中保存:

复制代码
Service Summary
Class Summary
Method Summary
API Summary
Business Flow
Architecture Summary
Database Usage
Dependency Explanation

而不是把所有源码都作为主要知识。


五十八、最终形成四层知识

建议:

复制代码
Layer 1:Raw Code

原始代码。

复制代码
Layer 2:Structural Knowledge

OpenRewrite 萃取。

复制代码
Layer 3:Semantic Knowledge

LLM 解释。

复制代码
Layer 4:Business Knowledge

业务流程、架构、领域知识。

结构:

复制代码
Raw Code
    ↓
AST/LST
    ↓
Structural Knowledge
    ↓
Semantic Knowledge
    ↓
Business Knowledge

五十九、整个项目的核心原则

如果只记住三句话:

第一

不要让 LLM 成为代码解析器。


第二

让 OpenRewrite / AST / Static Analysis 成为代码事实层。


第三

让 LLM 成为代码知识的语义层。

最终:

复制代码
OpenRewrite
    =
What is actually in the code?

LLM
    =
What does this code mean?

Agent
    =
What should I do with this knowledge?

六十、建议你的实际落地路线

如果这是一个真正的企业项目,我建议不要直接开发完整平台。

按照:

复制代码
第 1 周
    ↓
OpenRewrite 环境
    ↓
Class / Method Scanner

第 2 周
    ↓
Spring / REST
    ↓
API Knowledge

第 3 周
    ↓
Method Call
    ↓
Feign
    ↓
Service Dependency

第 4 周
    ↓
JPA / MyBatis
    ↓
SQL
    ↓
Database Lineage

第 5 周
    ↓
Kafka / Redis
    ↓
Event Graph

第 6 周
    ↓
PostgreSQL
    ↓
Neo4j

第 7 周
    ↓
5 个微服务
    ↓
验证跨服务关系

第 8 周
    ↓
150+ 微服务
    ↓
Incremental Scan

第 9 周
    ↓
LLM Semantic Layer

第 10 周
    ↓
RAG / Agent

六十一、最终项目目录

最终可以形成:

复制代码
software-intelligence-platform
│
├── scanner
│   ├── openrewrite
│   ├── maven
│   ├── gradle
│   ├── git
│   └── sql
│
├── knowledge-model
│
├── knowledge-store
│   ├── postgres
│   ├── pgvector
│   └── neo4j
│
├── semantic-engine
│   ├── architecture
│   ├── business-flow
│   ├── dependency
│   └── documentation
│
├── agent
│   ├── architecture-agent
│   ├── impact-agent
│   ├── migration-agent
│   ├── code-agent
│   └── documentation-agent
│
└── cli
    └── code-knowledge

六十二、下一步最值得实际开发的东西

不要马上开发 20 个 Scanner。

第一版只实现:

复制代码
1. ClassScanner
2. MethodScanner
3. AnnotationScanner
4. RestApiScanner
5. MethodCallScanner
6. FeignScanner

然后拿你实际的一个 Spring Boot 微服务跑。

最终必须得到:

复制代码
service.json
classes.json
methods.json
annotations.json
apis.json
method-calls.json
feign.json
relations.json

如果这 8 个文件能正确生成,整个项目就已经完成了最核心的 POC。

然后再扩展:

复制代码
MyBatis
JPA
SQL
Kafka
Redis
RabbitMQ
OpenAPI
Config

最后再接:

复制代码
PostgreSQL
Neo4j
Vector DB
LLM
Agent

六十三、参考资料

OpenRewrite 官方文档目前对 Maven Plugin、Recipe、Visitor、LST、Type Attribution 都有完整说明。Maven Plugin 支持 rewrite:runrewrite:dryRunrewrite:discover 等命令;Recipe 开发环境目前要求 JDK 21。

推荐重点阅读:

OpenRewrite Getting Started

OpenRewrite Maven Plugin Documentation

OpenRewrite Visitors

OpenRewrite Type Attribution

OpenRewrite LST Examples


总结

对于 150+ Spring 微服务,真正值得建设的不是一个简单的"代码 RAG"。

更准确地说,应该建设:

Software Intelligence Platform(软件智能知识平台)

它的核心链路是:

复制代码
Git
 ↓
OpenRewrite
 ↓
AST / LST / Type Attribution
 ↓
Structural Knowledge
 ↓
Knowledge Graph
 ↓
Semantic Knowledge
 ↓
RAG
 ↓
Agent

其中最重要的架构原则是:

事实由代码分析工具产生,语义由 LLM 产生,决策由 Agent 产生。

这样才能真正支撑后面的:

复制代码
代码理解
架构分析
影响分析
微服务治理
数据库迁移
系统现代化
技术债分析
API 分析
业务流程分析
AI Coding
Migration Agent
Architecture Agent

而不是单纯做一个"把代码塞进向量数据库"的 RAG 系统。

相关推荐
Sylvia33.1 小时前
LOL实时数据接入深度解析:从WebSocket到完整数据模型
java·网络·python·websocket·网络协议
2601_962071576 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
zww89491117 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
zww89491119 小时前
匿名树洞系统开发实战:从需求分析到部署指南
java·eclipse
黑马程序员毕设11 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
木井巳11 小时前
【BFS/DFS 解决 FloodFill 算法】太平洋大西洋水流问题
java·算法·leetcode·深度优先·广度优先·宽度优先·推荐算法
白山编程大哥11 小时前
Java 集合算法:从排序、查找到底层原理的实战指南
java·python·算法
devpotato11 小时前
缓存与数据库更新顺序不一致问题
java·数据库·redis
xcl092511 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·spring boot·需求分析