程云来 / 杭州
Back to Blog·Spring
·About 4 min

Spring(四):框架控制流程,代码只填变化部分

从 JdbcTemplate 和事件发布看模板方法、回调与扩展点,理解 Spring 为什么能减少样板代码而不接管业务判断。


固定流程为什么适合交给框架

数据库访问有一套反复出现的步骤:获取连接、创建语句、执行、映射结果、释放资源。每个业务方法都手写一遍,容易漏掉关闭连接和异常处理。

Spring 的模板类把不变步骤收起来,把变化部分留成回调:

java
List<Order> orders = jdbcTemplate.query(
    "select id, total from orders where user_id = ?",
    (resultSet, row) -> new Order(
        resultSet.getLong("id"),
        resultSet.getLong("total")
    ),
    userId
);

业务代码提供 SQL、参数和映射逻辑;连接管理、异常转换和资源释放由模板负责。

模板方法的结构

把一次查询抽象成伪代码,控制流会更清楚:

java
<T> T execute(Callback<T> callback) {
    Connection connection = dataSource.getConnection();
    try {
        return callback.run(connection);
    } catch (SQLException error) {
        throw translate(error);
    } finally {
        connection.close();
    }
}

框架控制主流程,Callback 是扩展点。这个思想也出现在任务执行器、HTTP 客户端、事务模板和测试生命周期中。

正在绘制图表…
查看 Mermaid 源码
flowchart LR
    app[业务代码] --> template[Spring 模板]
    template --> open[准备资源]
    open --> callback[调用回调]
    callback --> cleanup[统一清理]
    cleanup --> app

Mermaid 大图

可滚动查看图表,点击缩放比例可恢复 100%。按 Esc 关闭。

事件把不必要的直接依赖拆开

创建订单后,积分、通知和统计不一定要成为 OrderService 的同步依赖。可以发布一个领域事件:

java
record OrderCreated(String orderId) {}

@Service
class OrderService {
    private final ApplicationEventPublisher events;

    void createOrder(Order order) {
        save(order);
        events.publishEvent(new OrderCreated(order.id()));
    }
}

@Component
class PointsListener {
    @EventListener
    void onOrderCreated(OrderCreated event) {
        points.addFor(event.orderId());
    }
}

发布者只依赖事件发布器,不需要知道有多少个监听者。监听者可以独立增加或移除,但事件处理是否需要事务、是否允许异步,仍然要明确配置。

扩展点不是“随便插代码”

一个好的扩展点有清晰的输入、输出和执行时机:

  1. 模板负责哪些固定步骤;
  2. 回调可以改变哪些局部行为;
  3. 异常会被谁转换或传播;
  4. 资源由谁创建、谁释放。

如果这些边界说不清,扩展点就会变成隐藏控制流。读 Spring 源码时,可以先找模板类的主方法,再找它调用的回调接口和后置处理器。

这套思想如何迁移到自己的代码

当多个模块重复同一条可靠流程时,可以先画出不变步骤,再把业务差异收敛为接口或回调:

text
固定流程:校验 → 执行 → 记录 → 清理
变化部分:校验规则、执行动作、记录格式

不要为了复用而强行抽象。只有当流程稳定、变化点重复出现,模板和扩展点才会减少复杂度。

下一篇会解释 Spring Boot 的自动配置:当这些容器、模板和扩展点越来越多时,框架如何根据条件替我们完成默认组装。

参考:JdbcTemplateApplication Events