什么是回调(callback)机制?
它不限于Java,而是通用的编程机制。
回调的三个阶段:
- 声明回调:我发了一个帖子,说我后续会继续更新
- 注册回调:楼下网友订阅了我的帖子等更新
- 触发回调:我更新了,调用当初的声明回调代码,来通知所有订阅(注册回调)的网友
回调在设计模式中的使用:
- 策略模式
- 模板模式
- 观察者模式
- 访问者模式
此外:
- 事件总线
- 监听器
- 过滤器
- 某功能预留的客制化前置后置处理
- 对接口实现类的调用(创建接口=声明回调;实现接口=注册回调;调用实现类=触发回调)
- 故此推理:代理也是回调(反射也是?)
都算回调的应用
回调与正常调用的区别:
正常调用:框架开发API,我们调用来使用框架的类和逻辑
(我们 调 框架)(高层 调 底层)
回调:框架的API无法满足我们的调用需求,我们需要自己写一个类注册回调,来触发框架已有的回调机制,从而让框架来调用使用我们的类和逻辑
(框架 调 我们)(底层 反过来 调 高层)
关于声明回调的人有什么必要要这么弄?
就是把功能外包,增加他框架的拓展性
因为在实际开发中,一些耗费时间的工作交给扔出去让其他线程做,自身流程继续。
当交出去的工作做完了,它发一个消息回来,这就叫回调。
所以框架开发者留出可回调的余地,让后续使用框架的程序员能够注册和触发回调,实现客制化、高拓展性、且还可通过异步减少重量级业务对主线程的影响,此外它本质还是个解耦操作。
回调的本质:
有两个类 A B
在A中包含一个B的引用。(A关联B)
B中方法使用A对象作为参数。(B依赖A)
A方法1中调用B的方法2(同时将A对象作参数传给B)
B方法2执行完业务代码后再用A的对象(回)调A的方法3
在A调用B方法2时、或B调用方法3(回调方法)时,如果开启新的线程,就是异步,否则就是同步回调
回调俗称:钩子(Hook)
回调函数:钩子函数
如何理解 “被回调”,“谁对谁回调”的概念
首先:回调函数 会 被 (底层)回调
其次:回调函数(callback function)就是高层的客制化逻辑,被底层(框架)回调的函数
关于 A是对B的一个回调 这类术语的理解(以Spring为例):
Spring5 中 InitializingBean接口有288个实现类
而IoC生命周期管理的具体实现方法invokeInitMethods中包含了InitializingBean接口的抽象方法afterPropertiesSet()
invokeInitMethods方法能够接收bean的所有实现类(以Object形式),其中也包含了InitializingBean接口的实现类
所以在invokeInitMethods方法真正执行的时候,afterPropertiesSet一定会被具象地使用,并且能根据288种实现类做出288种不同的afterPropertiesSet逻辑,这些afterPropertiesSet的逻辑都在Runtime期间直接嵌入到invokeInitMethods的逻辑中,智能地执行匹配的invokeInitMethods方法。并且在未来它也还能够支持第289种逻辑,同时不用更改invokeInitMethods的底层代码,符合OCP开发原则。
在这个案例中:
- 具象的invokeInitMethods方法通过把抽象的afterPropertiesSet方法包含在内,实现了对未来被第三方回调的 - 声明
- 我们通过实现InitializingBean接口,并通过@Bean将其注册到Spring IoC容器中,实现了回调的 - 注册
- Spring IoC在运行时调用invokeInitMethods方法,在初始化我们实现InitializingBean接口的bean对象时,执行我们(第三方)自己客制化的afterPropertiesSet方法,实现了回调的 - 触发
其中:
具象的invokeInitMethods方法中包含的抽象的afterPropertiesSet方法 是对 InitializingBean接口的实现类中具象的afterPropertiesSet方法 的回调
这里前者是 A 后者是 B,故称为:A是对B的一个回调
Minecraft插件开发中回调的应用:
同步回调:
实现Listener写带有@EventHandler注解的onEventListener方法,
该方法就是Event触发时的回调方法,
它(Listener实现类)的注册需要在Plugin onEnable时注册Listener,
并在Runtime期间通过@EventHandler注解进行调度、和优先级管理等spigot回调函数的附加特性的执行
异步回调:
把你写的Listener方法变成异步即是异步回调
比如需要遍历大量方块的方法,改成异步就可以给主线程减负
业务中的异步回调案例:
案例1:
主线程中A开一个新线程去调用B的方法2,方法2结束前调用A的回调方法(方法3)对A进行通知,告诉它“我B做完事儿了”
案例2:
A类(我,代表主线程)去店里(B类)买菜,B说菜没有了,
但他有上菜通知业务(声明回调),我说:“那我走了(开始异步),
但有菜了回头给我来电话(注册回调)”
B说OK。三小时后,B上菜了,
给我(A类)来电话(触发回调),我就回去把菜买了。
期间B忙了三小时的进货,A也没被耽误菜之外其他的事情
Reference及相关阅读:
https://www.zhihu.com/question/25504849
https://www.cnblogs.com/ymczxy/p/4711122.html