news 2026/9/24 17:47:56

回调机制详解:从概念到 Spring 实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
回调机制详解:从概念到 Spring 实践

回调机制详解:从概念到 Spring 实践

一、什么是回调?

回调(Callback)是一种编程模式:把一段代码(函数或对象)作为参数传给另一个方法,由那个方法在合适的时机反过来调用这段代码。

通俗理解:你找别人帮忙办事,顺便留了个电话,告诉对方“事情办完了打这个电话通知我”。对方办完事后,按你留的电话联系你——这就是回调。你留的电话就是回调函数,对方在合适的时机“反过来调用”你。

二、为什么需要回调?

在没有回调的代码里,调用方必须等待被调用方执行完毕,然后自己处理后续逻辑。这导致:

  • 调用方必须知道被调用方的执行细节
  • 无法在特定时机插入自定义逻辑
  • 代码耦合度高,扩展困难

回调把这些控制权反转过来:被调用方在合适的时机主动通知调用方,调用方只需要提供“通知我时该做什么”。

这本质上是一种控制反转(IoC)——控制权从调用方转移到了被调用方。

三、回调的两种类型

1. 同步回调

调用方传入回调对象,被调用方在执行过程中直接调用回调方法,整个过程在同一个线程中完成,调用方会阻塞直到被调用方执行完毕。

// 回调接口publicinterfaceCallback{voidonComplete(Stringresult);}// 被调用方publicclassTaskExecutor{publicvoidexecute(Callbackcallback){System.out.println("开始执行任务");Stringresult="任务完成";// 执行完毕后回调callback.onComplete(result);}}// 调用方publicclassClient{publicstaticvoidmain(String[]args){TaskExecutorexecutor=newTaskExecutor();executor.execute(newCallback(){@OverridepublicvoidonComplete(Stringresult){System.out.println("收到回调:"+result);}});}}

输出:

开始执行任务 收到回调:任务完成

2. 异步回调

调用方传入回调对象后立即返回,被调用方在另一个线程中执行任务,完成后通过回调通知调用方。调用方不阻塞。

publicclassAsyncTaskExecutor{publicvoidexecute(Callbackcallback){newThread(()->{System.out.println("异步任务开始");try{Thread.sleep(1000);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}callback.onComplete("异步任务完成");}).start();System.out.println("调用方继续执行其他逻辑");}}

输出:

调用方继续执行其他逻辑 异步任务开始 (1 秒后) 异步任务完成

四、回调的常见实现形式

1. 接口回调

最经典的形式。定义一个接口,调用方实现接口,被调用方持有接口引用并调用。

publicinterfaceEventListener{voidonEvent(Stringevent);}

2. Lambda 表达式回调

Java 8 之后,函数式接口可以用 Lambda 简化。

publicclassTaskExecutor{publicvoidexecute(Consumer<String>callback){Stringresult=doSomething();callback.accept(result);}}

3. 匿名内部类回调

Java 8 之前常用的写法,现在逐渐被 Lambda 取代。

executor.execute(newCallback(){@OverridepublicvoidonComplete(Stringresult){System.out.println(result);}});

五、Spring 中的回调机制

Spring 框架大量使用了回调机制,理解回调是理解 Spring 扩展点的关键。

1. Bean 生命周期中的回调

Spring 在 Bean 创建过程中,会在不同阶段回调 Bean 实现的方法:

@ComponentpublicclassMyBeanimplementsInitializingBean,DisposableBean{@OverridepublicvoidafterPropertiesSet(){// 属性填充完成后,Spring 回调此方法System.out.println("初始化回调");}@Overridepublicvoiddestroy(){// 容器关闭时,Spring 回调此方法System.out.println("销毁回调");}}

@PostConstruct@PreDestroy也是回调:

@ComponentpublicclassMyBean{@PostConstructpublicvoidinit(){// Spring 在 Bean 初始化阶段回调}@PreDestroypublicvoidcleanup(){// Spring 在容器关闭时回调}}

2. Aware 接口回调

Bean 实现 Aware 接口后,Spring 会回调对应方法,把容器资源传进来:

@ComponentpublicclassMyBeanimplementsBeanNameAware,ApplicationContextAware{@OverridepublicvoidsetBeanName(Stringname){// Spring 回调,传入 Bean 名称}@OverridepublicvoidsetApplicationContext(ApplicationContextcontext){// Spring 回调,传入 ApplicationContext}}

3. BeanPostProcessor 回调

BeanPostProcessor是 Spring 最重要的回调扩展点。容器在创建每个 Bean 时,都会回调所有注册的BeanPostProcessor

@ComponentpublicclassMyBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){// 初始化前回调returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){// 初始化后回调(AOP 代理在这里生成)returnbean;}}

4. 事件监听回调

Spring 的事件机制也是回调:

@ComponentpublicclassMyEventListener{@EventListenerpublicvoidhandleEvent(ApplicationReadyEventevent){// 应用启动完成后,Spring 回调此方法System.out.println("应用已就绪");}}

5. JdbcTemplate 回调

JdbcTemplate中的RowMapperResultSetExtractor是典型的回调接口:

List<User>users=jdbcTemplate.query("SELECT * FROM user",newRowMapper<User>(){// 回调对象@OverridepublicUsermapRow(ResultSetrs,introwNum)throwsSQLException{// JdbcTemplate 遍历结果集时,回调此方法Useruser=newUser();user.setId(rs.getLong("id"));user.setName(rs.getString("name"));returnuser;}});

JdbcTemplate负责管理连接、执行 SQL、遍历结果集,但“每一行如何映射为对象”这个逻辑由调用方通过回调提供。

6. 事务回调

TransactionTemplate使用回调封装事务:

transactionTemplate.execute(newTransactionCallbackWithoutResult(){@OverrideprotectedvoiddoInTransactionWithoutResult(TransactionStatusstatus){// 事务内执行的逻辑,由 TransactionTemplate 回调userDao.save(user);orderDao.save(order);}});

TransactionTemplate负责开启事务、提交/回滚事务,具体业务逻辑由回调提供。

六、回调 vs 普通方法调用

对比维度普通方法调用回调
控制方向调用方主动调用被调用方被调用方在合适时机调用调用方
执行时机调用方决定被调用方决定
代码耦合调用方依赖被调用方双方都依赖接口,解耦
扩展性修改被调用方才能扩展传入不同的回调实现即可扩展
典型场景工具类方法事件处理、生命周期钩子、模板方法

七、回调的本质

回调的本质是将行为参数化。正常情况下,我们传给方法的是数据(字符串、数字、对象)。回调把“行为”(一段逻辑)也作为参数传递,让被调用方在合适的时机执行这段行为。

这带来了两个核心好处:

  • 解耦:调用方不需要知道被调用方的内部实现,只需要提供一个回调接口的实现。
  • 扩展:被调用方的代码不变,通过传入不同的回调实现,可以改变程序行为。

回调也是模板方法模式的基础。模板方法定义流程骨架,具体步骤由回调填充。Spring 的JdbcTemplateTransactionTemplate都是这个思路。

八、总结

维度核心要点
定义把一段代码作为参数传给另一个方法,由对方在合适时机调用
本质行为参数化,控制反转
类型同步回调(阻塞)、异步回调(不阻塞)
实现形式接口、Lambda、匿名内部类
Spring 中的应用生命周期回调、Aware 接口、BeanPostProcessor、事件监听、JdbcTemplate、事务模板
核心价值解耦、扩展、控制反转

回调不是什么高深的技术,而是一种思维方式:我把“做什么”告诉你,你决定“什么时候做”。理解回调,就能理解 Spring 为什么能在不修改业务代码的情况下,插入事务、日志、缓存等横切逻辑——因为它把扩展点设计成了回调接口,让开发者可以“留个电话,等通知”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 17:47:55

16:Python语法-字符串str

一、字符串1、一个字符串可以存放任意数量的字符。如&#xff1a;"hello" cwc """vwerv"""。2、字符串是有序的&#xff0c;每个字符都有其对应的下标&#xff0c;与列表一致。3、字符串不可变、有序、可遍历。二、字符串切片与列表切…

作者头像 李华
网站建设 2026/9/24 17:46:59

Oracle迁移国产库最怕什么?不可逆风险的四个关口与实测验证方法

大家好&#xff0c;我是数据库小学妹 &#x1f44b;我踩过的坑&#xff0c;你别再踩。 上周跟一个正在做去 O 的朋友吃饭&#xff0c;聊到他们上线前的最后一晚。他说全组通宵没干别的&#xff0c;就干了一件事&#xff1a;把"万一不行怎么回去"写成方案。三十多页的…

作者头像 李华
网站建设 2026/9/24 17:46:36

iPSC多谱系分化如何选Laminin亚型?LN521、LN111、LN511、LN411、LN332应用解析

摘要&#xff1a; 人体基底膜中的Laminin并不是单一蛋白&#xff0c;不同α、β、γ链组合形成不同亚型&#xff0c;并在多能干细胞巢、神经、血管、胰岛、皮肤、心肌和骨骼肌等组织中呈现不同表达模式。因此&#xff0c;iPSC定向分化中的Laminin选型不能简单理解为“所有流程都…

作者头像 李华
网站建设 2026/9/24 17:45:28

【Matlab】运动目标无人机视觉跟随控制实现

【Matlab】运动目标无人机视觉跟随控制实现 一、引言 随着智能无人机技术的快速迭代,无人机自主跟随飞行已经成为智能巡检安防监测野外追踪物资跟随运输等场景的核心功能。传统无人机跟随作业多依靠人工遥控或GPS定点跟随模式,存在明显的技术短板。GPS跟随依赖卫星定位信号…

作者头像 李华
网站建设 2026/9/24 17:45:20

基于 Java Spring Boot 的育儿所服务管理系统设计与实现

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 1. 引言 随着社会对婴幼儿照护服务需求的持续增长&#xff0c;育儿所&#xff08;托育机构&#xff09;的日常管理面临越来越多的挑战。传统的人工登记、纸质台账和分散…

作者头像 李华