传统企业的代码还能这么“卷”?

TPS计算员
2026-03-24 14:30
阅读 1168

去年冬天,北京那场大雪下得特别邪乎。我裹着羽绒服在地铁十号线上晃了一个小时,到公司时头发都结了霜——不是浪漫,是通勤的痛。作为一名扎根传统制造业数字化转型一线的Java开发,我每天面对的不只是业务逻辑和数据库表,还有老旧系统、模糊需求,以及永远赶不上上线日期的项目 deadline。

我们做的,说白了就是把“老师傅的经验”搬进系统里。听起来高大上,实则天天和 Excel 表格、手工台账斗智斗勇。但今年初,一个新项目彻底改变了我对“传统企业技术栈”的认知。而这个转折点,竟然是因为一个 AI 编程助手——Amazon Q(没错,就是 AWS 家那个)和国产大模型“通义千问”同时闯入了我的 IDE。

今天不吹牛,也不画饼,就聊聊我在真实项目中如何把这两个工具用起来,顺带做了几轮性能优化的实战经历。


起因:领导说“要快”,但没说怎么快

事情还得从今年3月说起。我们正在推进一个“供应链协同平台”的二期重构。一期是典型的单体架构,Spring Boot + MyBatis + MySQL,跑在物理机上,响应时间动不动就500ms+。产品经理拍着胸脯说:“这次一定要快!用户反馈页面加载太慢,影响下单效率。”

运维同事翻了个白眼:“你让后端查十几张表连表查询,前端还一次拉1000条数据,能快才怪。”

我呢?坐在 Mac 前面默默打开了 JProfiler。结果不出所料:80% 的时间花在 N+1 查询上,缓存几乎没用,序列化还用的默认 Jackson 配置。

更离谱的是,团队里两位老同事还在用 Windows 开发(别问,问就是“习惯了”),而我这台 M1 Max 虽然编译快如闪电,但一部署到测试环境就各种水土不服——毕竟测试服务器还是 CentOS 6(对,你没看错,2024年还在用)。

就在这个节骨眼上,公司 IT 部门突然宣布试点 Amazon Q Developer。理由很朴素:“隔壁互联网公司都在用 AI 写代码,咱们也试试,省点人力。”

说实话,一开始我是嗤之以鼻的。AI?写 CRUD 还行,真要优化复杂业务逻辑?怕不是给我埋雷。但架不住领导天天催进度,加上自己也好奇,干脆装上试试。


初探 Amazon Q:不是银弹,但能当“外挂”

Amazon Q 集成到 VS Code 后,第一感觉是“聪明但话多”。比如我选中一段慢 SQL:

List<Order> orders = orderMapper.selectByUserId(userId);
for (Order order : orders) {
    List<Item> items = itemMapper.selectByOrderId(order.getId());
    order.setItems(items);
}

右键“Explain this code”,它立刻指出:“检测到 N+1 查询问题,建议使用 JOIN 或批量查询。”
接着点“Suggest optimization”,它直接生成了 MyBatis 的 <resultMap> 配置,支持一对多嵌套查询——虽然语法有点小瑕疵,但思路完全正确。

更骚的操作是,当我写注释 // TODO: optimize cache strategy,它居然主动建议:“是否考虑使用 Caffeine 本地缓存 + Redis 二级缓存?以下是配置示例……”

那一刻,我承认,有点香。

但很快问题来了:Amazon Q 对中文业务术语理解很差。我们有个字段叫“工单完结率”,它愣是理解成“工厂订单完成速度”,生成的聚合逻辑完全跑偏。这时候,我转头试了试阿里云的 通义千问(Qwen)。

出乎意料!通义千问对中文业务场景的理解明显更接地气。我输入:“我们有个制造业项目,需要计算每个车间的日产能达成率,数据来自 MES 系统,有延迟,怎么设计缓存和补偿机制?”
它不仅给出了基于时间窗口的滑动缓存策略,还提醒:“注意 MES 数据可能重复上报,建议加幂等校验。”

两个工具各有千秋:

  • Amazon Q:英文文档、AWS 生态集成强,适合基础设施层优化(比如 Lambda 冷启动、RDS 参数调优)
  • 通义千问:中文语境理解好,业务逻辑建模更贴近国内实际

我把它们当成“左右护法”:底层性能调优问 Amazon Q,业务规则建模问通义千问。效果?开发效率至少提升30%——不是它替我写代码,而是帮我少走弯路。


实战:综合优化一个核心接口

我们的核心接口 /api/v1/supply-chain/dashboard 要展示供应商交付准时率、库存周转、在途物流等6个维度数据。原始实现是串行调用6个 Service,平均耗时 1.2s。

第一步:并行化 + 异步

我先用 CompletableFuture 把串行改成并行:

public DashboardDTO getDashboard(String tenantId) {
    CompletableFuture<OnTimeDelivery> deliveryFuture = 
        CompletableFuture.supplyAsync(() -> deliveryService.getOnTimeRate(tenantId));
    
    CompletableFuture<InventoryTurnover> inventoryFuture = 
        CompletableFuture.supplyAsync(() -> inventoryService.getTurnover(tenantId));
    
    // ... 其他4个
    
    return new DashboardDTO(
        deliveryFuture.join(),
        inventoryFuture.join(),
        // ...
    );
}

但问题来了:线程池用默认的 ForkJoinPool.commonPool(),在高并发下会阻塞主线程。Amazon Q 提醒我:“建议自定义线程池,并设置合理的队列和拒绝策略。”

于是加了个配置:

@Configuration
public class AsyncConfig {
    @Bean("dashboardExecutor")
    public Executor dashboardExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(16);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("dashboard-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

然后在 @Async("dashboardExecutor") 上标注。

第二步:缓存击穿防护

高峰期 DB CPU 直接飙到90%。排查发现是缓存失效瞬间大量请求打到数据库。通义千问建议:“用 Redis 分布式锁 + 本地缓存双保险。”

我采用了 Caffeine + Redis 的二级缓存方案:

private final LoadingCache<String, DashboardDTO> localCache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(30, TimeUnit.SECONDS)
    .build(key -> loadFromRedisOrDb(key));

private DashboardDTO loadFromRedisOrDb(String key) {
    String redisKey = "dashboard:" + key;
    String json = redisTemplate.opsForValue().get(redisKey);
    if (json != null) {
        return JSON.parseObject(json, DashboardDTO.class);
    }

    // 双重检查 + 分布式锁
    Boolean locked = redisTemplate.opsForValue().setIfAbsent("lock:" + key, "1", Duration.ofSeconds(5));
    if (Boolean.TRUE.equals(locked)) {
        try {
            DashboardDTO dto = computeExpensiveDashboard(key); // 真实计算
            redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(dto), Duration.ofMinutes(5));
            return dto;
        } finally {
            redisTemplate.delete("lock:" + key);
        }
    } else {
        // 等待一小会再读缓存
        Thread.sleep(50);
        return loadFromRedisOrDb(key); // 递归重试
    }
}

这里踩了个坑:Thread.sleep 在高并发下可能引发线程堆积。后来改成了自旋 + 指数退避,稳定多了。

第三步:序列化瘦身

前端抱怨 JSON 太大,加载慢。一看,一个 Dashboard DTO 序列化后 80KB!里面嵌套了太多冗余字段。

我用了 Jackson 的 @JsonView 做字段裁剪:

public class DashboardDTO {
    public interface Summary {}
    public interface Detail extends Summary {}

    @JsonView(Summary.class)
    private BigDecimal onTimeRate;

    @JsonView(Detail.class)
    private List<DeliveryRecord> recentDeliveries; // 只在详情页需要
}

Controller 层根据请求参数动态切换:

@GetMapping("/dashboard")
public ResponseEntity<DashboardDTO> getDashboard(
        @RequestParam(defaultValue = "summary") String view) {
    
    DashboardDTO dto = dashboardService.getDashboard(tenantId);
    
    if ("detail".equals(view)) {
        return ResponseEntity.ok().body(dto); // 默认返回全部
    } else {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setConfig(mapper.getSerializationConfig().withView(DashboardDTO.Summary.class));
        String json = mapper.writeValueAsString(dto);
        return ResponseEntity.ok().body(JSON.parseObject(json, DashboardDTO.class));
    }
}

响应体积直接降到 25KB,前端加载快了一倍。


效果对比:数字不会骗人

优化前后,我们在预发环境做了压测(JMeter,100 并发,持续 5 分钟):

指标 优化前 优化后 提升
平均响应时间 1240 ms 280 ms 77% ↓
P99 延迟 2100 ms 450 ms 79% ↓
DB CPU 使用率 88% 42% 52% ↓
GC 暂停时间 120 ms/min 35 ms/min 71% ↓

最爽的是,上周五上线后,产品经理居然主动在群里@我说:“这次真的快了!用户反馈很好!” —— 这在我职业生涯里,还是头一回。


心得:工具是辅助,思考才是核心

回头看这段经历,Amazon Q 和通义千问确实帮了大忙,但它们从来不是“替代者”。比如:

  • Amazon Q 建议用 JOIN 解决 N+1,但在我们分库分表的场景下根本不可行,最后还是用批量 ID 查询;
  • 通义千问推荐的“滑动时间窗口缓存”,在实际落地时发现内存泄漏,得手动加清理逻辑。

真正的价值在于:它们把我从重复劳动中解放出来,让我有精力思考更高层的架构问题。比如现在,我开始琢磨要不要引入 GraphQL 让前端按需取字段,或者用 Flink 做实时指标计算。

另外,传统企业搞优化,光技术不够,还得“向上管理”。我特意把性能数据做成图表,给领导汇报时强调:“每降低100ms延迟,预计每月可减少XX小时用户等待时间,相当于节省XX人天成本。” —— 果然,资源申请顺利多了。


写在最后

有人说传统企业技术落后,但我觉得,恰恰是因为约束多、历史包袱重,才更考验工程师的综合能力。你不仅要懂代码,还得懂业务、懂沟通、懂妥协。

每天坐一小时地铁来公司,打开 MacBook,面对满屏的 legacy code,我偶尔也会烦躁。但每当看到自己优化的接口让一线工人少等几秒钟,或者让仓库管理员少点几次刷新——那种成就感,是纯互联网项目给不了的。

技术探索没有高低贵贱。在制造业的数字化浪潮里,我们这些“老 Java 人”,一样可以玩出花来。

对了,如果你也在传统企业搞转型,欢迎交流。不过别问我 Windows 怎么配 JDK——我只负责 Mac 端的优雅开发,Windows?那是测试同学的战场 😏

评论 0

最热最新
暂无评论
TPS计算员Lv.1
0
影响力
0
文章
0
粉丝