前言作为开发者,你是否经常看到下图的场景?那么当你看到这种图的时候,是不是会有这样的疑惑:为什么res对象不为null,谁给你赋值的,这个命名是我输的方式吗?我没有在这里传递一个值?下面以前端axios组件为向导,深入探讨一下回调方法。什么是回调在计算机编程中,回调:是指通过函数参数将对某段可执行代码的引用传递给其他函数,供其他函数调用的编程思想。它的目的是允许低级代码调用在高层定义的子程序。通俗地说就是:A类调用了B类中的一个方法C,然后B类中的方法C又调用了A类中的方法D,其中D是回调方法。代码示例:packagecom.aha.commons.callback;importlombok.Data;importlombok.experimental.Accessors;importlombok.extern.slf4j.Slf4j;importjava.util.HashMap;importjava.util.Map;/***模拟前端调用接口组件讲解回调过程**@authorWT*date2021/11/10*/interfaceCallbackInterface{//远程调用接口后的回调方法voidcallback(RPCResponserpcResponse);}/***调用接口后返回的对象*/@Data@Accessors(chain=true)classRPCResponse{privateIntegercode;私人字符串消息;privateMapdata;}/***远程调用组件*/@Slf4jpublicclassRPCModule{publicvoidcall(Stringurl,Mapparams,CallbackInterfacecallbackInterface){log.info("Theremote调用接口地址为:{},参数为:{}",url,params);log.info("处理远程调用接口响应数据封装响应体...");HashMapdata=newHashMap<>();data.put("名字","啊哈");data.put("年龄",24);RPCResponseresponse=newRPCResponse().setCode(200).setMessage("请求接口成功").setData(data);log.info("调用接口完成,执行回调方法...");//重点:这里是子类实现的回调方法callbackInterface.callback(response);}}@Slf4jclassCustomFrontPage{publicstaticvoidmain(String[]args){HashMapparams=newHashMap<>();params.put("名字","啊哈");//模拟前端远程调用流程——查询用户名为ahanewRPCModule().call("/api/users",params,res->{//重点:这里是RPCModule调用后回调的方法上游获取响应信息res有值的原因是调用RPCModule时传过来的Overif(res.getCode().equals(200)){log.info("请求后端接口成功,回调执行成功,获取到的响应信息为:{},获取到的响应数据为:{}",res.getMessage(),res.getData());}else{log.error("请求到后台接口成功,但是回调失败,错误响应码为:{}",res.getCode());}});}}流程解释:上面的例子模拟了在前端使用Ajax调用后端接口的过程。关注CustomFrontPage类中的主要方法。该方法的作用是构造请求参数,发起远程调用接口。这个过程主要是CustomFrontPage类调用RPCModule的call方法,RPCModule的call方法执行后,回调CustomFrontPage类中匿名内部类重写的回调方法。在这个过程中,RPCModule是底层代码,CustomFrontPage类中匿名内部类重写的回调方法是高层定义的子程序。实现回调的核心是子类对象引用的传递。在上面的例子中,使用了一个匿名内部类来传递对底层代码的引用。回调的分类同步回调:阻塞当前线程,回调方法执行完毕后,继续执行后面的代码。异步回调:不阻塞当前线程,可以继续执行下面的代码。同步回调的实现方法就是上面的方法,这里不再赘述。其实一般的远程请求接口应该是异步的。异步回调实现如果实现异步回调,最容易想到的方案就是多线程。packagecom.aha.commons.callback;importlombok.extern.slf4j.Slf4j;importorg.springframework.util.ObjectUtils;importjava.util.HashMap;importjava.util.Map;/***远程调用组件*/@Slf4jpublicclassASyncRPCModule{publicvoidcall(Stringurl,Mapparams,CallbackInterfacecallbackInterface){log.info("远程调用接口地址为:{},参数为:{}",url,params);log.info("处理远程调用接口响应数据封装响应体...");HashMapdata=newHashMap<>();data.put("名字","啊哈");数据。把(“年龄”,24);RPCResponseresponse=newRPCResponse().setCode(200).setMessage("请求接口成功").setData(data);log.info("调用接口完成,执行回调方法..");//重点:这里调用的是子类callbackInterface.callback(response)实现的回调方法;}}@Slf4jclassASyncCustomFrontPage{publicstaticvoidmain(String[]args){HashMapparams=newHashMap<>();params.put("名字","啊哈");//异步回调->最简单的方法是使用多线程newThread(()->//模拟前端远程调用的过程——查询用户名为ahanewASyncRPCModule().call("/api/users",params,res->{if(ObjectUtils.isEmpty(res)||ObjectUtils.isEmpty(res.getCode())){log.error("请求后端接口异常,响应对象为null");return;}//重点:这里是RPCModule调用上游获取响应信息后回调的方法,res之所以有值,是调用RPCModule时传递的值if(res.getCode().equals(200)){log.info("请求后端接口成功,回调执行成功,获取到的响应信息为:{},获取到的响应数据为:{}",res.getMessage(),res.getData());}else{log.error("请求后端接口成功,执行失败回调。错误响应码为:{}",res.getCode());}})).start();log.info("因为是异步执行,所以主线程没有阻塞,我在调用接口下面,但还是有可能我先执行");}}