大家好我是小悟。一、背景与转变在AI代码助手普及之前我的Java编码流程典型是理解需求 → 翻阅Java文档/Stack Overflow → 手写POJO/Service/Controller → 调试NullPointerException → 修改 → 重复。Spring框架的样板代码尤其耗费时间。现在AI彻底改变了这一切。我的角色从“代码的生产者”变成了“代码的架构师和审阅者”——我决定架构、接口设计、异常处理策略AI负责生成实体类、Repository、Service骨架我负责校验事务边界、线程安全、性能优化。二、详细步骤第一步需求理解与拆解人工主导做什么拿到一个任务后我先自己拆解成清晰的模块和子任务定义好接口契约。示例假设要做一个“用户上传图片并自动添加水印”的功能。我的拆解Java技术栈视角Controller层PostMapping接收MultipartFile参数校验Service层业务逻辑——校验格式、调用水印服务、保存文件水印处理组件独立WatermarkService支持文字/图片水印存储策略本地文件系统或OSS可配置异步处理大图用Async避免阻塞异常处理ControllerAdvice全局处理配置管理application.yml中配置水印位置、大小限制等为什么要人工做AI不了解你的项目是否已存在FileStorageService、使用的是什么OSS SDK、日志规范是什么。拆解得越清晰AI生成的代码越能直接融入现有项目。第二步与AI对话式设计人机协作做什么把拆解好的模块逐个与AI讨论技术方案。这不是简单的“给我代码”而是像跟资深同事讨论设计。示例对话我我要用Spring Boot 3.2 Java 17实现图片上传加水印。图片可能10MB要求不阻塞主线程。水印支持文字可配置内容、位置、透明度和图片水印。你有什么方案建议AI建议方案Controller立即返回202 Accepted和任务ID用AsyncThreadPoolTaskExecutor异步处理水印处理用javax.imageio.ImageIO需注意大图内存问题处理完成后更新数据库状态前端轮询或WebSocket通知大图建议先用Image.getScaledInstance或第三方库如TwelveMonkeys处理需要注意ImageIO默认支持的格式有限需要添加依赖异步任务中的异常要妥善记录。我ImageIO处理大图确实容易OOM有没有更好的方案AI可以考虑使用ImageMagick命令行通过ProcessBuilder稳定但依赖外部使用thumbnailator库封装了ImageIO但做了优化使用JDK 21的虚拟线程处理大量并发根据你的环境建议用thumbnailator代码简单且内存控制较好。这一步的价值AI帮你想到Java特有的问题内存溢出、线程池配置、流未关闭等你在对话中修正方案。第三步生成代码骨架与细节AI主导做什么方案确定后让AI生成代码。我习惯按模块分层生成先实体类再Repository再Service最后Controller。示例提示词请用Spring Boot 3.2 Java 17写一个图片上传和水印服务实体类ImageTask包含id(UUID)、原始文件名、原图路径、水印图路径、状态(PENDING/PROCESSING/COMPLETED/FAILED)、创建时间、错误信息Repository继承JpaRepositoryServiceuploadAndWatermark(MultipartFile file, String watermarkText)保存原图创建任务记录触发异步水印处理返回任务IDprocessWatermarkAsync(taskId, watermarkText)异步方法用thumbnailator添加文字水印右下角半透明字体大小根据图片比例计算ControllerPOST /api/images/upload返回任务IDGET /api/images/task/{id} 查询状态配置文件支持app.watermark.textMyApp 2026、app.watermark.positionbottom-right、app.max-file-size5MBAI的输出// ImageTask.java Entity Table(name image_task) Data NoArgsConstructor AllArgsConstructor public class ImageTask { Id GeneratedValue(strategy GenerationType.UUID) private UUID id; private String originalFileName; private String originalPath; private String watermarkedPath; Enumerated(EnumType.STRING) private TaskStatus status; private LocalDateTime createdAt; private String errorMessage; PrePersist protected void onCreate() { createdAt LocalDateTime.now(); status TaskStatus.PENDING; } } // WatermarkService.java Service Slf4j public class WatermarkService { Value(${app.watermark.text:MyApp 2026}) private String watermarkText; Autowired private ImageTaskRepository taskRepository; Async(watermarkExecutor) public CompletableFutureVoid processWatermarkAsync(UUID taskId, String watermarkText) { // 更新状态为PROCESSING ImageTask task taskRepository.findById(taskId).orElseThrow(); task.setStatus(TaskStatus.PROCESSING); taskRepository.save(task); try { // 使用thumbnailator添加水印 File originalFile new File(task.getOriginalPath()); File outputFile new File(task.getWatermarkedPath()); BufferedImage original ImageIO.read(originalFile); int fontSize Math.max(20, original.getWidth() / 20); // 添加文字水印 Graphics2D g original.createGraphics(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); g.setFont(new Font(Arial, Font.BOLD, fontSize)); g.setColor(Color.WHITE); FontMetrics fm g.getFontMetrics(); int textWidth fm.stringWidth(watermarkText); int textHeight fm.getHeight(); int x original.getWidth() - textWidth - 20; int y original.getHeight() - 20; g.drawString(watermarkText, x, y); g.dispose(); // 保存水印图 String format originalFile.getName().substring(originalFile.getName().lastIndexOf(.) 1); ImageIO.write(original, format, outputFile); // 更新状态为COMPLETED task.setStatus(TaskStatus.COMPLETED); taskRepository.save(task); } catch (Exception e) { log.error(水印处理失败, taskId: {}, taskId, e); task.setStatus(TaskStatus.FAILED); task.setErrorMessage(e.getMessage()); taskRepository.save(task); } return CompletableFuture.completedFuture(null); } }我的工作复制代码到IDE但不急着运行。我逐行检查依赖注入是否正确Autowiredvs 构造器注入事务边界异步方法中Transactional无效需要手动处理资源释放ImageIO.read和original.createGraphics()没有显式关闭虽然有GC但最好用try-with-resources这里需要改进配置项读取是否合理第四步人工审阅与调整人工主导做什么AI生成的代码通常有90%可用但总有需要微调的地方。实际操作针对上面的代码发现问题AI用Graphics2D直接修改原图BufferedImage然后覆盖保存不对它读的是原图画完直接写出没有保存原图版本。我需要修改逻辑先复制一份原图到临时文件再对复制品加水印。性能问题ImageIO.read(originalFile)会把整个10MB图片加载到内存高并发下会OOM。我改用thumbnailator的流式处理或者限制并发数。线程池配置AI只用了Async没配置线程池。我补充ThreadPoolTaskExecutor配置Configuration EnableAsync public class AsyncConfig { Bean(name watermarkExecutor) public Executor watermarkExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(2); executor.setMaxPoolSize(5); executor.setQueueCapacity(100); executor.setThreadNamePrefix(watermark-); executor.initialize(); return executor; } }文件存储AI直接用了绝对路径我需要改成从配置读取存储根目录并自动创建目录。格式处理AI写的保存格式提取逻辑有bug比如jpg和jpeg我手工修复。关键原则AI是副驾驶方向盘在我手里。我不会让任何一行我不理解的代码进入代码库。第五步测试生成与调试人机协作做什么让AI帮我生成JUnit测试用例然后运行测试把错误信息直接抛给AI辅助修复。示例我请为上面的WatermarkService.processWatermarkAsync方法写JUnit 5测试用例使用Mockito mock ImageIO和文件操作。覆盖场景正常添加水印、图片格式不支持、文件不存在。AI生成测试SpringBootTest ExtendWith(MockitoExtension.class) class WatermarkServiceTest { Mock private ImageTaskRepository taskRepository; InjectMocks private WatermarkService watermarkService; Test void testProcessWatermarkSuccess() throws Exception { // Mock任务 ImageTask task new ImageTask(); task.setId(UUID.randomUUID()); task.setOriginalPath(/tmp/test.jpg); task.setWatermarkedPath(/tmp/output.jpg); when(taskRepository.findById(any())).thenReturn(Optional.of(task)); // 准备测试图片 BufferedImage testImage new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB); when(ImageIO.read(any(File.class))).thenReturn(testImage); // 执行 watermarkService.processWatermarkAsync(task.getId(), Test).get(); // 验证最终状态为COMPLETED ArgumentCaptorImageTask captor ArgumentCaptor.forClass(ImageTask.class); verify(taskRepository, atLeastOnce()).save(captor.capture()); assertThat(captor.getValue().getStatus()).isEqualTo(TaskStatus.COMPLETED); } }我运行测试发现一个bug测试失败NullPointerException at WatermarkService.processWatermarkAsync - g.setFont() 原因在headless环境下Graphics2D的字体渲染可能失败。我测试在GitHub Actions无头环境下失败了提示GraphicsEnvironment.getLocalGraphicsEnvironment()返回null。请修复代码使其在无头环境下也能运行。AI提供修复方案使用BufferedImage的createGraphics()之前先设置系统属性java.awt.headlesstrue通常Spring Boot默认已设置或者改用Font.createFont()加载字体。我采纳后测试通过。第六步文档与注释AI辅助做什么代码写完后让AI根据代码生成JavaDoc、OpenAPI注解SpringDoc和commit message。示例请为上面的WatermarkService类生成标准的JavaDoc注释包括参数说明、异常说明、使用示例。AI输出/** * 图片水印处理服务 * * p异步处理图片水印添加支持文字水印和图片水印。 * 处理结果会更新到ImageTask实体中可通过状态查询接口获取结果。/p * * p使用示例/p * pre * CompletableFutureVoid future watermarkService.processWatermarkAsync(taskId, My Watermark); * future.whenComplete((result, ex) - { * if (ex ! null) log.error(处理失败, ex); * }); * /pre * * author Your Name * since 1.0.0 * see ImageTask * see TaskStatus */ Service public class WatermarkService { ... }第七步代码审查与重构人机协作做什么把写好的复杂代码块交给AI让它提出重构建议尤其是Java特有的设计模式、性能优化。示例提示词请审查下面这段批量处理图片的代码是否存在线程安全问题是否可以用Stream并行流优化是否违反了单一职责原则AI可能会指出Async方法中直接修改实体并保存如果同一个任务被并发调用会有竞态条件用Version乐观锁可以把水印绘制逻辑抽取成独立的WatermarkRenderer接口便于单元测试和扩展图片水印文件路径拼接用Path而不是字符串避免跨平台问题三、完整流程图示需求输入 ↓ [人工] 拆解任务 → 定义接口/实体/分层 ↓ [人机] 技术方案讨论Spring版本、线程池、格式兼容 ↓ [AI] 生成POJO Repository → 代码块 [AI] 生成Service含异步→ 代码块 [AI] 生成Controller DTO → 代码块 ↓ [人工] 审阅调整事务边界、资源释放、配置抽取 ↓ [AI] 生成JUnit测试 → 测试代码 ↓ [人工] 运行测试 → 发现bug如headless、OOM ↓ [人机] 调试修复循环直到通过 ↓ [AI] 生成JavaDoc OpenAPI注解 → 文档 ↓ [人工] 最终审查 Git提交 ↓ [人机] 重构建议设计模式、性能优化四、详细总结1. 核心变化方面以前现在样板代码手写POJO的getter/setter/toStringLombok AI生成瞬间完成Spring配置翻文档写BeanAI生成配置类微调即可异常处理忘记try-catch或处理不当AI生成全局ControllerAdvice单元测试懒得写或覆盖率低AI生成骨架只需补充断言第三方集成读SDK文档、写样板AI给出最佳实践代码2. AI使用技巧明确JDK版本提示词中包含“Java 17”避免AI生成Java 8过时API或Java 21专有特性指定框架版本“Spring Boot 3.2 Jakarta EE不是javax”提供现有类信息把已有的BaseEntity、ResultVO类代码贴给AI让它生成的代码遵循项目规范注意Lombok提醒AI使用Data、Builder等减少冗余代码内存敏感代码人工复核AI经常忽略Java的OOM风险大文件、集合无限增长、流未关闭3. 效率提升数据任务类型以前耗时现在耗时变化写JPA实体类 Repository10分钟2分钟-80%写Service CRUD 分页15分钟4分钟-73%写全局异常处理20分钟5分钟-75%写单元测试Mockito20分钟5分钟-75%Debug Spring循环依赖15分钟8分钟-47%4. 常见陷阱与应对陷阱表现应对策略版本混淆AI用了javax.persistence而不是jakarta.persistence明确指定“Jakarta EE 10”事务失效Async方法内调Transactional不生效提醒AI“异步方法中事务如何正确使用”内存泄漏不关闭Stream、Connection人工检查所有资源类是否用了try-with-resources线程安全SimpleDateFormat、ArrayList在并发下崩溃AI生成代码后人工检查是否用了线程安全类Null安全没有NotNull、Optional滥用让AI生成时强制“使用java.util.Optional避免null”5. 最后以前开发效率常被样板代码拖累。AI的到来让开发体验发生了质变Lombok AI两者结合几乎消灭了POJO的所有手写工作Spring生态整合AI熟悉Spring全家桶的配置方式节省了大量查文档时间类型安全仍需要你Java的强类型对AI来说“容易生成但容易错”比如泛型擦除后的类型转换、Stream的类型推断需要你人工校验实践用AI生成标准代码Controller/Service/Repository人工编写核心算法和复杂业务逻辑让AI帮忙写测试和文档最终执行严格的Code Review你Review AI的代码AI让开发从“打字密集型”变成了“决策密集型”。你的价值不再是敲出多少行代码而是做出多少个正确的技术决策。谢谢你看我的文章既然看到这里了如果觉得不错随手点个赞、转发、在看三连吧感谢感谢。那我们下次再见。您的一键三连是我更新的最大动力谢谢山水有相逢来日皆可期谢谢阅读我们再会我手中的金箍棒上能通天下能探海