Java回调机制小结
1. 什么是回调?
模块之间的调用方式有以下三种:同步调用,异步调用和回调。
同步调用是一种阻塞式调用,是我们平时最常使用的调用方式。类A的方法a()调用类B的方法b()时,要等到方法b()执行完后a()才继续往下执行。
异步调用是为了解决同步调用可能阻塞而导致整个流程卡住的一种调用方式,类A的方法a()会新起一个线程的方式去调用类B的方法b(),然后继续往下执行。这样不管b()执行多久都不会阻塞到a()的执行。
回调是一种双向的调用方式,类A的方法a()调用类B的方法b(),在b()的执行过程中会主动调用类A的callback()方法。
2. 回调如何来实现?
通常回调是通过以下几个步骤来实现的:
- 类A实现CallBack-callback接口
- 类A包含一个类B的实例
- 类B中有一个CallBack类型参数的方法b(CallBack callback)
- 类A的a()在调用b(CallBack callback)时,传递自身引用(this)作为参数
- b(CallBack callback)在执行过程中,可以通过callback实例来调用A的callback()方法
3. 回调的例子
举个例子:有一天,小明的老婆在逛商场时看到一件很喜欢的一款衣服,但是没有她的尺码,要过几天新到的衣服才有她的尺码,于是小明的老婆留下她的电话号码,商场的销售员会在新衣服到了之后第一时间通知她,而小明的老婆可以去做自己的事情,不必在商场等待新到的衣服。
代码示例:
回调接口
/**
* 回调接口
* @author ZhuYuan
*
*/
public interface CallBack {
void newClothArrived();
}
顾客类(步骤中的类A)
/**
* 顾客类(步骤1的类A),实现CallBack接口
* @author ZhuYuan
*
*/
public class Customer implements CallBack{
//销售员对象,对应步骤2中的类B的实例
private Seller seller;
public Customer(Seller seller){
this.seller = seller;
}
//对应步骤4
public void shopping(){
seller.sell(this);
}
@Override
public void newClothArrived() {
System.out.println("The new cloth you want is arrvied...");
}
}
销售员类(步骤中的类B)
/**
* 销售员类(类B)
* @author ZhuYuan
*/
public class Seller {
//类B中的CallBack类型参数的方法(步骤3)
public void sell(CallBack callback){
//模拟销售员在新衣服到货之前去做其他事情,比如为其他顾客服务
try{
Thread.sleep(3000);
}catch(InterruptedException e){
e.printStackTrace();
}
//回调,告诉顾客想要的新衣服到货了(步骤5)
callback.newClothArrived();
}
}
测试类
/**
* 测试类
* @author ZhuYuan
*
*/
public class CallBackTest {
public static void main(String[] args){
Seller seller = new Seller();
Customer customer = new Customer(seller);
customer.shopping();
}
}
4. 回调的适用场景
大家都使用过Filter和Interceptor,这两者最大的一个区别就是Filter是基于回调函数,需要容器的支持,没有容器就无法回调doFilter()方法,Interceptor是基于Java的反射机制,与容器无关。
在我们使用框架时,通常是直接使用框架提供的API,但是当框架的API不能满足需求的时候,我们需要框架来调用自己的方法。在这种情况下,我们不可能去修改框架,而是会通过实现框架的预留回调接口来满足个性化需求,从而让框架来调用我们自己的实现。
5. 小结
在系统架构设计阶段,往往很多时候上层模块很难预料下层模块如何实现,此时我们只需要定义好回调接口,当下层模块在调用上层模块时,根据实际需要实现回调接口,并通过注册或者参数的方式传入上层模块,这样就实现了下层调用上层,上层会调用下层的具体实现。
回调是一种思想,一种调用机制,它允许底层代码调用高层定义的子程序,增强程序的灵活性,和反射有着异曲同工之妙。其核心是回调方(类A)如何讲本身引用传递给调用方(类B),这样调用方在调用过程中就可以告诉回调方想要的信息。