回调函数(callback Function),顾名思义,就是为被调用方所反过来调用的函数,比如说客户程序Client调用了服务端Server中的某个函数serverMethod,在执行过程中Server又反过来调用Client中的某个函数clientMethod(出于扩展机制的考虑),那么这个被Server调用的函数clientMethod就叫做回调函数,那么既然是为被调用方反过来调用的方法那么被调用方法如何得知这个方法的定义呢 ?那么就需要调用方和调用方就需要事先有个约定,这个约定就是“回调接口”,双方安装回调接口规范编写程序,就可以是实现回调逻辑,
回调的作用:通常是Server端不知道如何处理或处理逻辑依赖Client端逻辑,就通过回调的方式进入到Client的方法栈,回调也可以通常也用来实现Server端的扩展机制,如Server端开发回调接口,不同的回调接口实现以完成不同的业务需求,在spring框架中使用了很多的回调设计,如spring的hibernate集成(在hibernate中执行以获取响应结果),如spring提供的jndi工具 JndiTemplate , 也是利用回调实现,源码片段如下:
/**
* Callback interface to be implemented by classes that need to perform an
* operation (such as a lookup) in a JNDI context. This callback approach
* is valuable in simplifying error handling, which is performed by the
* JndiTemplate class. This is a similar to JdbcTemplate's approach.
*/
public interface JndiCallback {
/**
* Do something with the given JNDI context.
* Implementations don't need to worry about error handling
* or cleanup, as the JndiTemplate class will handle this.
*/
Object doInContext(Context ctx) throws NamingException;
}
/**
* Execute the given JNDI context callback implementation.
* org.springframework.jndi.JndiTemplate 的源代码
*/
public Object execute(JndiCallback contextCallback) throws NamingException {
Context ctx = createInitialContext();
try {
return contextCallback.doInContext(ctx);
}
finally {
try {
ctx.close();
}
catch (NamingException ex) {
logger.warn("Could not close JNDI InitialContext", ex);
}
}
}
public Object lookup(final String name) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Looking up JNDI object with name [" + name + "]");
}
return execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
Object located = ctx.lookup(name);
if (located == null) {
throw new NameNotFoundException(
"JNDI object with [" + name + "] not found: JNDI implementation returned null");
}
return located;
}
});
}
public void bind(final String name, final Object object) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Binding JNDI object with name [" + name + "]");
}
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.bind(name, object);
return null;
}
});
}
public void rebind(final String name, final Object object) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Rebinding JNDI object with name [" + name + "]");
}
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.rebind(name, object);
return null;
}
});
}
public void unbind(final String name) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Unbinding JNDI object with name [" + name + "]");
}
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.unbind(name);
return null;
}
});
}
二、原理图
三、示例代码
class AppContext {
String data;
public AppContext(String data) {
this.data = data;
}
Object process() {
return "process:" + data;
}
}
interface CallBackInterface {
Object doInContext(AppContext context);
}
class ServerPoint {
AppContext appContext = new AppContext("ServerData");
Object execute(CallBackInterface callBack) {
return callBack.doInContext(appContext);
}
}
public class CallbackTest {
static ServerPoint serverPoint = new ServerPoint();
public static void main(String[] args) {
Object executeData = serverPoint.execute(new CallBackInterface() {
public Object doInContext(AppContext context) {
String process = (String) context.process();
System.out.println("客户端使用使用服务器资源AppContext处理数据");
return process;
}
});
System.out.println(executeData);
}
}
结果:
客户端使用使用服务器资源AppContext处理数据
process:ServerData