preface
As a developer, do you often see the scenario in the following figure?
When you see this graph, do you have such doubts: why is this res object not null? Who gave you the value? This naming is my method? I didn't pass it value here? Now let's take the front-end axios component as a guide to discuss the callback method in depth.
What is a callback
In computer programming, callback refers to the programming idea of passing the reference of an executable code to other functions through function parameters for other functions to call.
Its purpose is to allow the underlying code to call subroutines defined at a high level.
The popular way is to call a method C in class B, then C in B class calls D in class A. in this way, D is callback method.
Code example:
package com.aha.commons.callback; import lombok.Data; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; /** * Simulate the front-end calling interface component to explain the callback process * * @author WT * date 2021/11/10 */ interface CallbackInterface { // Method of callback after remote calling interface void callback(RPCResponse rpcResponse); } /** * The object returned after calling the interface */ @Data @Accessors(chain = true) class RPCResponse { private Integer code; private String message; private Map<String, Object> data; } /** * Remote call component */ @Slf4j public class RPCModule { public void call (String url, Map<String,String> params, CallbackInterface callbackInterface) { log.info("The remote calling interface address is:{},The parameters are:{}",url,params); log.info("Process remote call interface response data and encapsulate the response body..."); HashMap<String, Object> data = new HashMap<>(); data.put("name", "aha"); data.put("age", 24); RPCResponse response = new RPCResponse().setCode(200).setMessage("Request interface succeeded").setData(data); log.info("Call interface complete,Execute callback method..."); // Important: the callback method implemented by the subclass is called here callbackInterface.callback(response); } } @Slf4j class CustomFrontPage { public static void main(String[] args) { HashMap<String, String> params = new HashMap<>(); params.put("name", "aha"); // Simulate the process of remote call from the front end - query the user named aha new RPCModule().call("/api/users", params, res -> { // Key point: This is the callback of this method after RPCModule calls the upstream to obtain the response information. The reason why res has value is passed through when RPCModule calls if (res.getCode().equals(200)) { log.info("Request for backend interface succeeded,Execute successful callback,The response information obtained is:{},The response data obtained are:{}", res.getMessage(), res.getData()); } else { log.error("Request for backend interface succeeded,Execution failure callback,The wrong response code is:{}", res.getCode()); } }); } }
Process explanation: the above example simulates the process that the front end uses Ajax to call the back-end interface.
Focus on the main method in the CustomFrontPage class. The function of this method is to build request parameters and initiate remote call interface. This process is the process that the main of the CustomFrontPage class calls the call method of RPCModule, and after the call method of RPCModule is executed, it calls back the callback method overridden by the anonymous inner class in the CustomFrontPage class.
In this process, RPCModule is the underlying code, and the callback method rewritten by the anonymous inner class in the CustomFrontPage class is a high-level defined subroutine.
The core of implementing callback is the passing of subclass object reference. In the above example, the anonymous inner class is used to pass the reference to the underlying code.
Classification of callbacks
- Synchronous callback: block the current thread. After the callback method is executed, continue to execute the following code.
- Asynchronous callback: you can continue to execute the following code without blocking the current thread.
The implementation method of synchronous callback is the above method, which will not be repeated here. In fact, the general remote request interface should be asynchronous.
Implementation of asynchronous callback
For asynchronous callback, the easiest way to think of is multithreading.
package com.aha.commons.callback; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import java.util.HashMap; import java.util.Map; /** * Remote call component */ @Slf4j public class ASyncRPCModule { public void call (String url, Map<String,String> params, CallbackInterface callbackInterface) { log.info("The remote calling interface address is:{},The parameters are:{}",url,params); log.info("Process remote call interface response data and encapsulate the response body..."); HashMap<String, Object> data = new HashMap<>(); data.put("name", "aha"); data.put("age", 24); RPCResponse response = new RPCResponse().setCode(200).setMessage("Request interface succeeded").setData(data); log.info("Call interface complete,Execute callback method..."); // Important: the callback method implemented by the subclass is called here callbackInterface.callback(response); } } @Slf4j class ASyncCustomFrontPage { public static void main(String[] args) { HashMap<String, String> params = new HashMap<>(); params.put("name", "aha"); // Asynchronous callback - > the simplest way is through multithreading new Thread(() -> // Simulate the process of remote call from the front end - query the user named aha new ASyncRPCModule().call("/api/users", params, res -> { if (ObjectUtils.isEmpty(res) || ObjectUtils.isEmpty(res.getCode())) { log.error("Request backend interface exception, The response object is null"); return; } // Key point: This is the callback of this method after RPCModule calls the upstream to obtain the response information. The reason why res has value is passed through when RPCModule calls if (res.getCode().equals(200)) { log.info("Request for backend interface succeeded,Execute successful callback,The response information obtained is:{},The response data obtained are:{}", res.getMessage(), res.getData()); } else { log.error("Request for backend interface succeeded,Execution failure callback,The wrong response code is:{}", res.getCode()); } }) ).start(); log.info("Because it is executed asynchronously,The main thread is not blocked,I'm under the calling interface,But it's still possible that I did it first"); } }