前言
在程序中,通常想要获取信息需要去主动调用,比如调用get方法获取值。
但是这样有些场景就满足不了,比如你想要获取的信息产生的时间不确定。当然,你可以做个循环一直去get,直到get到想要的信息为止。但这并不是一个好办法。
回调,就是被动通知。我调个接口,并没有立刻获取到结果,没关系,等结果出来之后被调用者自动给我返回。这样的好处是我不需要重复去查询结果,解耦代码。
.
实现机制
现在通过买票的例子进行分析
场景:我买票,售票员通知我出票结果
分析:关键词是被通知,很显然,我的出票结果是被售票员通知的,但是怎么通知?很多网文一笔带过,难道真实情况真的是这么简单不值一提吗?
真相:实际上管理员是不能直接通知到我,而是有个中间人,对,我有个朋友叫小明,是他帮我转告售票员的"口述的"。所以真实的情况是:我在售票窗口买票,给了钱之后,就把身边的小明扣住,然后转身对售票大叔说,待会出票了你跟他说就行了,他会转告给我。于是,过一会,出结果了,小明就屁颠屁颠跑来说:“有结果了,出票成功.”
原理:上面的例子中小明就是回调载体。而小明是定义好的,我在我需要得到通知的事件中交给售票员的,并且在小明身上定义了一些协议,比如通知消息的格式等等。然后他就负责返回我要的消息。
对象:
我–>Me
售票员–>Conductor
小明–>Callback
.
实现代码
/**
* 回调,这是小明
* @Author TanXiongzhan
*/
public interface Callback {
void returnResult(String msg);
}
/**
* 售票员
*
* @Author Tan
*/
public class Conductor {
public void printTickets(Callback callback) {
System.out.println("售票员开始处理 . . . ");
try {
Thread.currentThread();
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("售票员处理完毕 . . . ");
// 出票完成,通知出票结果(这里是发起回调的地方)
callback.returnResult("出票完成");
}
}
/**
* 这是我
* @Author Tan
*/
public class Me {
// 指定一个售票人(待会他出票后要通知我)
Conductor conductor = new Conductor();
/*
* 同步回调
* 方法:买票
* 内容:内容:把回调对象(小明)传给售票员
*/
public void buyTicketsSyn(Callback callback) {
conductor.printTickets(callback);
}
/*
* 异步回调
* 方法:买票
* 内容:把回调对象(小明)传给售票员
*/
public void buyTicketsSynASyn(Callback callback) {
new Thread(new Runnable() {
public void run() {
conductor.printTickets(callback);
}
}).start();
}
}
/**
* 程序入口
* @Author Tan
*/
public class Main {
public static void main(String[] args) {
// 定义一个回调
Callback callback = new Callback() {
@Override
public void returnResult(String msg) {
System.out.println("小明通知:" + msg);
}
};
Me me = new Me();
System.out.println("我准备买票----");
// me.buyTicketsSyn(callback); //发起买票(同步回调)
me.buyTicketsSynASyn(callback); //发起买票(异步回调)
System.out.println("我在等待出票----");
}
}
结果:
至此,一个简单的回调梳理就结束了。
自己写回调
现在通常都在spring 上开发,那么如何编写回调,并且给外部暴露回调接口呢?往下,进入进阶模式
实现说明:将回调实现抽象起来,然后暴露回调函数,其他地方需要重写回调时继承即可
然后将回调接口注入到spring 容器中即可。
简单比喻就是,我让小明出票了通知我,但是小明比较懒,就让小红来帮忙转达消息(小红继承小明,重写小明回调函数)
/**
* 回调,这是一个小明
* @Author TanXiongzhan
*/
public interface Callback {
void returnResult(String msg);
}
/**
* 将回调暴露出去,继承者重写结果返回方法即可
* @Author Tan
*/
public abstract class CallbackAbstract implements Callback {
@Override
public void returnResult(String msg) {
// System.out.println("小明通知:" + msg);
returnResultPublic(msg);
}
public abstract void returnResultPublic(String msg);
}
/**
* 第三方继承回调实现(监听回调)
* 这是小红
* @Author Tan
*/
@Service
public class CallbackImpl extends CallbackAbstract {
@Override
public void returnResultPublic(String msg) {
System.out.println("小红通知:" + msg);
}
}
/**
* 售票员
*
* @Author Tan
*/
public class Conductor {
public void printTickets(Callback callback) {
System.out.println("售票员开始处理 . . . ");
try {
Thread.currentThread();
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("售票员处理完毕 . . . ");
// 出票完成,通知出票结果(这里是发起回调的地方)
callback.returnResult("出票完成");
}
}
/**
* 这是我
* @Author TanXiongzhan
*/
public class Me {
// 指定一个售票人(待会他出票后要通知我)
Conductor conductor = new Conductor();
/*
* 同步回调
* 方法:买票
* 内容:内容:把回调对象(小明)传给售票员
*/
public void buyTicketsSyn(Callback callback) {
conductor.printTickets(callback);
}
/*
* 异步回调
* 方法:买票
* 内容:把回调对象(小明)传给售票员
*/
public void buyTicketsSynASyn(Callback callback) {
new Thread(new Runnable() {
public void run() {
conductor.printTickets(callback);
}
}).start();
}
}
/**
* 在实际应用中,用注入的方式声明回调接口
* 谁实现,调用谁的回调函数
* @Author Tan
*/
@Service
public class MainSpring implements InitializingBean {
@Autowired
private Callback callback;
@Override
public void afterPropertiesSet() throws Exception {
Me me = new Me();
System.out.println("我准备买票----");
// me.buyTicketsSyn(callback); //发起买票(同步回调)
me.buyTicketsSynASyn(callback); //发起买票(异步回调)
System.out.println("我在等待出票----");
}
}
运行结果:
.
.
.
完毕