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:run、rewrite:dryRun、rewrite: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 系统。

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi3 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号3 天前
java函数式编程--入门基础
java·编程·函数式编程