1. OpenAI Codex 开发指南:从入门到精通
作为一名长期从事企业级应用开发的工程师,我最近深入研究了OpenAI Codex这个革命性的AI编程助手。经过数周的实践验证,我整理出这份全面的开发指南,希望能帮助开发者们高效利用这个强大的工具。
1.1 Codex核心能力解析
OpenAI Codex不仅仅是一个代码补全工具,它是一个全方位的AI软件工程助手。在我的实际使用中,它展现了以下核心能力:
- 智能代码生成:根据自然语言描述生成功能完整的代码块,自动适配项目结构和编码规范
- 代码理解与解释:快速解析复杂代码库,特别是对遗留系统的理解能力令人印象深刻
- 自动化调试:能识别常见错误模式,提供针对性的修复建议
- 测试覆盖:自动生成单元测试和集成测试用例,显著提升代码质量
- 重构支持:安全地进行代码重构,保持功能一致性的同时改善代码结构
1.2 开发环境准备
在开始使用Codex前,需要做好以下环境准备:
基础工具链配置
bash复制# 推荐开发环境
- Java 11+ (推荐Amazon Corretto)
- MySQL 8.0+ (生产环境建议使用云数据库)
- Linux开发环境(Ubuntu 20.04 LTS或CentOS 7+)
- Spring Boot 2.7.x + Spring Cloud 2021.x
IDE插件安装
对于Java开发者,我强烈建议在IntelliJ IDEA中安装Codex插件:
- 打开IDEA的插件市场
- 搜索"OpenAI Codex"
- 安装并重启IDE
- 通过ChatGPT账号完成认证
专业提示:在团队开发环境中,建议统一配置AGENTS.md文件,定义项目级的代码规范和约束条件,这能显著提升Codex的输出质量。
2. Codex深度集成实践
2.1 Spring Boot项目集成
在Spring Boot项目中,Codex可以极大提升开发效率。以下是我的典型工作流程:
实体类生成
java复制// 用Codex生成JPA实体类
/**
生成一个User实体类,包含id(Long)、username(String)、email(String)、createdAt(LocalDateTime)字段
使用Lombok简化代码,配置JPA注解和校验注解
*/
@Getter
@Setter
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
@Size(min = 3, max = 50)
private String username;
@Column(nullable = false, unique = true)
@Email
private String email;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt = LocalDateTime.now();
}
Repository接口增强
java复制// 让Codex扩展JPA Repository
/**
为User实体创建Repository接口
添加通过email查找用户的方法
添加统计用户名包含特定关键词的用户数量的方法
*/
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
@Query("SELECT COUNT(u) FROM User u WHERE u.username LIKE %:keyword%")
long countByUsernameContaining(@Param("keyword") String keyword);
}
2.2 数据库优化实践
Codex在数据库优化方面表现出色,特别是在MySQL性能调优上:
索引优化建议
sql复制-- 让Codex分析并优化以下查询
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'COMPLETED' ORDER BY created_at DESC;
-- Codex给出的优化建议:
-- 1. 添加复合索引
ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);
-- 2. 改写查询只获取必要字段
SELECT id, order_number, total_amount FROM orders
WHERE user_id = 100 AND status = 'COMPLETED'
ORDER BY created_at DESC;
事务处理最佳实践
java复制// 使用Codex优化事务管理
/**
重构以下服务方法,添加适当的事务管理
考虑隔离级别和传播行为
处理可能的异常情况
*/
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public OrderResult placeOrder(OrderRequest request) {
// 库存检查
Inventory inventory = inventoryRepository.findByProductId(request.getProductId())
.orElseThrow(() -> new BusinessException("Product not available"));
if (inventory.getStock() < request.getQuantity()) {
throw new BusinessException("Insufficient stock");
}
// 扣减库存
inventory.setStock(inventory.getStock() - request.getQuantity());
inventoryRepository.save(inventory);
// 创建订单
Order order = new Order();
// 设置订单属性...
orderRepository.save(order);
// 发送领域事件
eventPublisher.publishEvent(new OrderPlacedEvent(order));
return OrderResult.success(order.getId());
}
3. Linux环境下的高效开发
3.1 开发环境配置
在Linux服务器上配置Codex开发环境:
bash复制# 安装Codex CLI工具
curl -sSL https://install.openai.com/codex | bash
# 配置环境变量
echo 'export CODEX_CONFIG_DIR="$HOME/.codex"' >> ~/.bashrc
echo 'export PATH="$PATH:$HOME/.codex/bin"' >> ~/.bashrc
source ~/.bashrc
# 验证安装
codex --version
3.2 自动化脚本生成
Codex可以快速生成高效的Shell脚本:
bash复制# 生成一个监控Spring Boot应用的健康检查脚本
'''
编写一个bash脚本,每5分钟检查一次Spring Boot应用的健康状态
应用运行在8080端口,健康检查端点/actuator/health
如果检测到异常,发送邮件通知并尝试重启服务
记录所有检查结果到/var/log/app-monitor.log
'''
#!/bin/bash
APP_URL="http://localhost:8080/actuator/health"
LOG_FILE="/var/log/app-monitor.log"
ADMIN_EMAIL="admin@example.com"
while true; do
response=$(curl -sS -o /dev/null -w "%{http_code}" "$APP_URL")
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
if [ "$response" -eq 200 ]; then
echo "$timestamp - Application is healthy" >> "$LOG_FILE"
else
echo "$timestamp - ERROR: Application health check failed (Status: $response)" >> "$LOG_FILE"
echo "Application health check failed at $timestamp" | mail -s "Application Alert" "$ADMIN_EMAIL"
# 尝试重启服务
systemctl restart my-springboot-app
echo "$timestamp - Attempted to restart application" >> "$LOG_FILE"
fi
sleep 300
done
4. 高级功能与最佳实践
4.1 微服务架构支持
在Spring Cloud微服务环境中,Codex能帮助解决分布式系统的典型挑战:
Feign客户端生成
java复制// 让Codex创建一个Feign客户端接口
/**
为UserService创建一个Feign客户端
基础URL通过配置中心获取
包含以下端点:
- GET /api/users/{id}
- POST /api/users/search
- GET /api/users/me (需要JWT认证)
添加适当的错误处理和重试机制
*/
@FeignClient(name = "user-service", configuration = FeignConfig.class)
public interface UserServiceClient {
@GetMapping("/api/users/{id}")
ResponseEntity<UserDTO> getUserById(@PathVariable Long id);
@PostMapping("/api/users/search")
ResponseEntity<Page<UserDTO>> searchUsers(@RequestBody UserSearchCriteria criteria);
@GetMapping(value = "/api/users/me",
headers = {"Authorization={token}"})
ResponseEntity<UserDTO> getCurrentUser(@Param("token") String token);
}
// 配置类
@Configuration
public class FeignConfig {
@Bean
public Retryer retryer() {
return new Retryer.Default(1000, 5000, 3);
}
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}
分布式事务建议
Codex对分布式事务的处理建议非常实用��
code复制在微服务架构中处理订单创建和库存扣减的分布式事务,给出Java实现方案
建议采用Saga模式实现最终一致性:
1. 创建OrderService的Saga协调器
2. 定义以下步骤:
- 创建订单(可补偿)
- 扣减库存(可补偿)
- 支付处理(可补偿)
3. 为每个步骤实现补偿操作
4. 使用Axon框架或自定义事件总线实现
关键点:
- 每个参与服务提供补偿API
- 实现幂等性处理
- 添加事务日志表跟踪Saga状态
- 考虑设置超时机制
4.2 性能调优实战
JVM参数优化
bash复制# 让Codex为Spring Boot应用生成优化的JVM参数
'''
我们的Spring Boot应用有以下特点:
- 使用MySQL数据库
- 高频的HTTP请求处理
- 大量对象缓存
- 平均堆内存使用约2GB
生成适合的JVM启动参数
'''
# 推荐的JVM参数
JAVA_OPTS="-server -Xms4g -Xmx4g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=4 \
-XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
-XX:+ExplicitGCInvokesConcurrent -XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/java_heapdump.hprof \
-XX:NativeMemoryTracking=detail -Xlog:gc*:file=/var/log/gc.log:time,uptime:filecount=5,filesize=10m"
SQL查询优化
java复制// 优化复杂的JPQL查询
/**
优化以下查询,考虑添加适当的索引并重写查询语句:
*/
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.user.id = :userId AND o.status = 'COMPLETED' AND o.createdAt BETWEEN :start AND :end ORDER BY o.totalAmount DESC")
List<Order> findCompletedOrdersByUserAndDateRange(Long userId, LocalDateTime start, LocalDateTime end);
// Codex优化建议:
// 1. 数据库层面添加索引:
// ALTER TABLE orders ADD INDEX idx_user_status_date_amount (user_id, status, created_at, total_amount);
// 2. 重写查询避免笛卡尔积:
@Query(value = "SELECT o FROM Order o WHERE o.user.id = :userId AND o.status = 'COMPLETED' " +
"AND o.createdAt BETWEEN :start AND :end ORDER BY o.totalAmount DESC")
List<Order> findCompletedOrdersByUserAndDateRange(Long userId, LocalDateTime start, LocalDateTime end);
// 然后分批获取关联的items
@Query("SELECT i FROM OrderItem i WHERE i.order.id IN :orderIds")
List<OrderItem> findItemsByOrderIds(List<Long> orderIds);
5. 安全实践与故障排查
5.1 安全编码实践
Codex能帮助识别常见的安全漏洞并提供修复建议:
java复制// 让Codex检查以下代码的安全问题
@GetMapping("/user")
public User getUser(@RequestParam String id) {
return userRepository.findById(Long.parseLong(id)).orElse(null);
}
// Codex的安全建议:
/**
1. SQL注入风险:直接使用用户输入的ID参数
建议:使用预编译参数或JPA内置方法
2. 信息泄露:返回完整的User对象
建议:使用DTO投影只返回必要字段
3. 缺少输入验证:未验证id参数格式
建议:添加@Validated和校验注解
改进后的代码:
*/
@GetMapping("/user")
public UserDTO getUser(@RequestParam @Pattern(regexp = "\\d+") String id) {
Long userId = Long.valueOf(id);
return userRepository.findProjectedById(userId, UserDTO.class)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
}
5.2 常见问题排查
连接池问题诊断
bash复制# 让Codex帮助诊断数据库连接池问题
'''
我们的Spring Boot应用偶尔出现以下错误:
"Timeout waiting for connection from pool"
当前配置:
spring.datasource.hikari.maximum-pool-size=10
连接的是MySQL 8.0数据库
'''
# Codex的诊断建议:
1. 检查连接泄漏:
- 启用Hikari的leak detection阈值
spring.datasource.hikari.leak-detection-threshold=60000
2. 优化连接池配置:
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=5000
spring.datasource.hikari.max-lifetime=1800000
3. MySQL服务器端配置检查:
SHOW VARIABLES LIKE 'wait_timeout';
建议设置为大于连接池的max-lifetime
4. 添加监控端点:
management.endpoint.hikari.enabled=true
内存泄漏分析
Codex可以指导如何进行内存分析:
bash复制# 生成内存分析步骤
'''
我们的Java应用内存持续增长,怀疑有内存泄漏
使用Linux工具和JDK工具给出诊断步骤
'''
# Codex提供的诊断流程:
1. 监控内存使用趋势:
top -p $(pgrep -f my-springboot-app)
2. 获取堆转储:
jmap -dump:live,format=b,file=heapdump.hprof $(pgrep -f my-springboot-app)
3. 分析堆转储:
jhat heapdump.hprof
或使用Eclipse MAT工具
4. 检查GC日志:
添加JVM参数:
-Xlog:gc*:file=/var/log/gc.log:time,uptime:filecount=5,filesize=10m
5. 实时监控:
jstat -gc $(pgrep -f my-springboot-app) 1s
6. 分析线程栈:
jstack $(pgrep -f my-springboot-app) > thread_dump.log
6. 持续集成与部署
6.1 GitHub Actions集成
Codex可以优化CI/CD流水线配置:
yaml复制# 让Codex优化我们的Spring Boot项目GitHub Actions配置
'''
我们的项目使用:
- Java 17
- MySQL 8.0测试容器
- 需要运行单元测试和集成测试
- 构建Docker镜像推送到ECR
- 部署到Kubernetes集群
'''
name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ '*' ]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: testdb
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Build and test
run: ./mvnw verify -Dspring.profiles.active=ci
build-docker:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push
env:
ECR_REGISTRY: ${{ secrets.ECR_REGISTRY }}
ECR_REPOSITORY: my-springboot-app
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_SHA .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_SHA
deploy:
needs: build-docker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy to EKS
run: |
aws eks update-kubeconfig --name my-cluster
kubectl set image deployment/my-app my-app=$ECR_REGISTRY/$ECR_REPOSITORY:$GITHUB_SHA
6.2 Kubernetes部署优化
Codex可以生成优化的Kubernetes部署描述文件:
yaml复制# 让Codex为我们的Spring Boot应用生成Kubernetes部署文件
'''
应用特点:
- 需要连接MySQL和Redis
- 需要配置JVM参数
- 需要监控端点
- 需要水平自动扩展
- 生产环境需要资源限制
'''
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-springboot-app
spec:
replicas: 3
selector:
matchLabels:
app: my-springboot-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-springboot-app
spec:
containers:
- name: app
image: my-ecr-repo/my-springboot-app:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: JAVA_OPTS
value: "-Xms2g -Xmx2g -XX:+UseG1GC"
resources:
requests:
cpu: "1000m"
memory: "3Gi"
limits:
cpu: "2000m"
memory: "4Gi"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-springboot-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-springboot-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
7. 监控与可观测性
7.1 Prometheus监控配置
Codex可以帮助配置完善的监控系统:
yaml复制# 让Codex生成Spring Boot应用的Prometheus监控配置
'''
我们需要监控:
- JVM指标
- HTTP请求指标
- 数据库连接池
- 自定义业务指标
使用Micrometer和Prometheus
'''
# application.yml配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
http.server.requests: true
tags:
application: ${spring.application.name}
# 自定义指标示例
@RestController
public class OrderController {
private final MeterRegistry meterRegistry;
private final Counter orderCounter;
public OrderController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCounter = Counter.builder("orders.total")
.description("Total number of orders placed")
.tag("application", "order-service")
.register(meterRegistry);
}
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
orderCounter.increment();
// 处理订单逻辑...
}
}
# Prometheus配置示例
scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['my-springboot-app:8080']
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: '(.*):\d+'
replacement: '$1'
7.2 日志收集优化
yaml复制# 让Codex优化我们的日志配置
'''
使用Logback和ELK栈
需要结构化日志(JSON格式)
区分不同级别日志
包含MDC信息
'''
# logback-spring.xml配置
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="appName" source="spring.application.name"/>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"${appName}","env":"${spring.profiles.active}"}</customFields>
<includeContext>true</includeContext>
<includeMdc>true</includeMdc>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON"/>
<appender-ref ref="FILE"/>
</root>
<logger name="org.springframework" level="WARN"/>
<logger name="com.myapp" level="DEBUG"/>
</configuration>
8. 实际项目经验分享
8.1 复杂业务逻辑实现
在电商项目中,Codex帮助我快速实现了复杂的订单价格计算逻辑:
java复制// 让Codex实现一个包含多种优惠策略的价格计算器
/**
实现一个OrderPriceCalculator类,考虑以下优惠规则:
1. 会员等级折扣(普通会员5%,高级会员10%)
2. 满减优惠(满100减10,满200减25)
3. 优惠券折扣(百分比或固定金额)
4. 限时促销活动
5. 运费计算(根据重量和地区)
所有计算应保证线程安全,结果四舍五入到2位小数
*/
@Component
public class OrderPriceCalculator {
private static final BigDecimal DISCOUNT_REGULAR = new BigDecimal("0.95");
private static final BigDecimal DISCOUNT_PREMIUM = new BigDecimal("0.90");
public OrderCalculationResult calculate(Order order, User user, Coupon coupon, Promotion promotion) {
BigDecimal subtotal = calculateSubtotal(order.getItems());
// 会员折扣
BigDecimal memberDiscount = applyMemberDiscount(subtotal, user.getMemberLevel());
// 满减
BigDecimal fullReduction = applyFullReduction(memberDiscount);
// 优惠券
BigDecimal couponDiscount = applyCoupon(fullReduction, coupon);
// 促销活动
BigDecimal promotionDiscount = applyPromotion(couponDiscount, promotion);
// 运费
BigDecimal shippingFee = calculateShippingFee(order.getWeight(), order.getShippingRegion());
BigDecimal total = promotionDiscount.add(shippingFee);
return new OrderCalculationResult(
subtotal,
memberDiscount.subtract(subtotal).abs(),
fullReduction.subtract(memberDiscount).abs(),
coupon != null ? coupon.getDiscountAmount() : BigDecimal.ZERO,
promotion != null ? promotion.getDiscountAmount() : BigDecimal.ZERO,
shippingFee,
total
);
}
private BigDecimal applyMemberDiscount(BigDecimal amount, MemberLevel level) {
return switch (level) {
case PREMIUM -> amount.multiply(DISCOUNT_PREMIUM);
case REGULAR -> amount.multiply(DISCOUNT_REGULAR);
default -> amount;
}.setScale(2, RoundingMode.HALF_UP);
}
// 其他私有方法实现...
}
8.2 缓存策略优化
Codex帮助设计了高效的缓存策略:
java复制// 让Codex优化我们的缓存实现
/**
改进以下缓存服务,考虑:
1. 多级缓存(本地缓存+Redis)
2. 缓存击穿保护
3. 一致性哈希分布
4. 过期策略
5. 监控指标
使用Caffeine和Redis实现
*/
@Service
public class EnhancedCacheService {
private final Cache<String, Object> localCache;
private final RedisTemplate<String, Object> redisTemplate;
private final MeterRegistry meterRegistry;
public EnhancedCacheService(RedisTemplate<String, Object> redisTemplate,
MeterRegistry meterRegistry) {
this.redisTemplate = redisTemplate;
this.meterRegistry = meterRegistry;
this.localCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.recordStats()
.build();
// 注册缓存指标
meterRegistry.gauge("cache.local.size", localCache, Cache::estimatedSize);
}
@SuppressWarnings("unchecked")
public <T> T get(String key, Class<T> type, Supplier<T> loader, Duration ttl) {
// 先查本地缓存
T value = (T) localCache.getIfPresent(key);
if (value != null) {
meterRegistry.counter("cache.local.hits").increment();
return value;
}
// 使用Redis分布式锁防止缓存击穿
RLock lock = redissonClient.getLock("lock:" + key);
try {
lock.lock();
// 双重检查
value = (T) localCache.getIfPresent(key);
if (value != null) {
return value;
}
// 查Redis
value = (T) redisTemplate.opsForValue().get(key);
if (value != null) {
localCache.put(key, value);
meterRegistry.counter("cache.redis.hits").increment();
return value;
}
// 加载数据
value = loader.get();
if (value != null) {
redisTemplate.opsForValue().set(key, value, ttl);
localCache.put(key, value);
meterRegistry.counter("cache.loads").increment();
}
return value;
} finally {
lock.unlock();
}
}
}
9. 性能测试与优化
9.1 JMeter测试计划
Codex可以生成专业的性能测试计划:
xml复制<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.4.1">
<hashTree>
<!-- 测试计划 -->
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Spring Boot API 性能测试" enabled="true">
<stringProp name="TestPlan.comments">由Codex生成的性能测试计划</stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="baseUrl" elementType="Argument">
<stringProp name="Argument.name">baseUrl</stringProp>
<stringProp name="Argument.value">http://localhost:8080</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="threads" elementType="Argument">
<stringProp name="Argument.name">threads</stringProp>
<stringProp name="Argument.value">100</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</TestPlan>
<hashTree>
<!-- 线程组 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="API 负载测试" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">-1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${__P(threads,100)}</stringProp>
<stringProp name="ThreadGroup.ramp_time">60</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">300</stringProp>
<stringProp name="ThreadGroup.delay">0</stringProp>
</ThreadGroup>
<hashTree>
<!-- HTTP请求默认值 -->
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP请求默认值" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${baseUrl}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">6</stringProp>
</ConfigTestElement>
<hashTree/>
<!-- 登录请求 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="用户登录" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="username" elementType="HTTPArgument">
<stringProp name="Argument.name">username</stringProp>
<stringProp name="Argument.value">testuser</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="password" elementType="HTTPArgument">
<stringProp name="Argument.name">password</stringProp>
<stringProp name="Argument.value">password123</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<stringProp name="HTTPSampler.path">/api/auth/login</stringProp>
<stringProp name="HTTPSampler.contentType">application/json</stringProp>
</HTTPSamplerProxy>
<hashTree>
<!-- 提取token -->
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="提取Token" enabled="true">
<stringProp name="JSONPostProcessor.referenceNames">authToken</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.token</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">0</stringProp>
</JSONPostProcessor>
<hashTree/>
</hashTree>
<!-- 带认证的API请求 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="获取用户信息" enabled="true">
<stringProp name="HTTPSampler.method">GET</stringProp>
<stringProp name="HTTPSampler.path">/api/users/me</stringProp>
<collectionProp name="HTTPsampler.headers">
<elementProp name="" elementType="HTTPHeader">
<stringProp name="Header.name">Authorization</stringProp>
<stringProp name="Header.value">Bearer ${authToken}</stringProp>
</elementProp>
</collectionProp>
</HTTPSamplerProxy>
<hashTree/>
<!-- 聚合报告 -->
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="聚合报告" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename">report.csv</stringProp>
</Result
