第一:它的应用场景是什么?

if you call me ,i will call back。目前我接触到两种需要回调的需求

1、系统管理平台登录,登录所需要的人员和部门数据都是在另一个基础信息系统中。当基础信息中人员或者部门信息改变的时候,如果不通知其他系统,尤其是系统管理系统这种对于核心数据很关键的系统会造成数据不同步的问题,所以当基础信息中的数据增删改的时候就要通知其他系统。

2、小红小明做算术题,小明需要小红算数做作业,老婆婆需要小红算数算账,调用的都是小红计算器,小红接着调用特定的接口,小明和老婆婆各自不同实现。服务端提供一种公用的方法,但是各个客户端调用的时候有较小的差异,那么公用的方法放在服务端使用,存在差异的部分放在服务端自己实现。

(参考文章:http://blog.csdn.net/qq_30983519/article/details/52537613)

 

第二:它的实现原理是什么?

CallBack回调机制,它的本质是服务端调用客户端的逻辑,形式是服务端提供接口,而由客户端按照自己的需求具体实现。客户端先调用服务端的服务,服务端处理后再调用客户端逻辑。

 

第三:它的实现方式是什么?

第一个例子是计算器:

小红希望以后继续向小明提供计算服务,同时还能向老婆婆提供算账服务,甚至以后能够拓展其他人的业务,于是她向所有的顾客约定了一个办法,用于统一的处理,也就是自己需要的操作数和做完计算之后应该怎么做。这个统一的方法,小红做成了一个接口,提供给了大家,代码如下:

public interface doJob
{
public void fillBlank(int a, int b, int result);
}

同时,小红修改了自己的计算器,使其可以同时处理不同的实现了doJob接口的人,代码如下:

public class SuperCalculator
{
    public void add(int a, int b, doJob  customer)
    {
        int result = a + b;
        customer.fillBlank(a, b, result);
    }
}

小明和老婆婆拿到这个接口之后,只要实现了这个接口,就相当于按照统一的模式告诉小红得到结果之后的处理办法,按照之前说的使用内部类来做,小明代码如下:

public class Student
{
    private String name = null;

    public Student(String name)
    {        // TODO Auto-generated constructor stub
        this.name = name;
    }

    public void setName(String name)
    {        this.name = name;
    }

    public class doHomeWork implements doJob
    {

        @Override
        public void fillBlank(int a, int b, int result)
        {            // TODO Auto-generated method stub
            System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
        }

    }

    public void callHelp (int a, int b)
    {        new SuperCalculator().add(a, b, new doHomeWork());
    }
}

老婆婆:

public class Seller
{
    private String name = null;

    public Seller(String name)
    {        // TODO Auto-generated constructor stub
        this.name = name;
    }

    public void setName(String name)
    {        this.name = name;
    }

    public class doHomeWork implements doJob
    {

        @Override
        public void fillBlank(int a, int b, int result)
        {            // TODO Auto-generated method stub
            System.out.println(name + "求助小红算账:" + a + " + " + b + " = " + result + "元");
        }

    }

    public void callHelp (int a, int b)
    {        new SuperCalculator().add(a, b, new doHomeWork());
    }
}

测试代码:

public class Test
{
    public static void main(String[] args)
    {
        int a = 56;
        int b = 31;
        int c = 26497;
        int d = 11256;
        Student s1 = new Student("小明");
        Seller s2 = new Seller("老婆婆");

        s1.callHelp(a, b);
        s2.callHelp(c, d);
    }
}

第二:系统登录所需的部门人员数据变化

基础信息服务端代码:

import com.alibaba.dubbo.config.annotation.Service;

/**
 * 提供回调功能的Dubbo服务
 * @author yuankun
 * @version V1.0
 */
@Service(protocol = { "dubbo" })
public interface CallbackService {
    
    /**
     * 向回调服务中注册一个监听器
     * @param listener 监听器
     */
    void addListener(CallbackListener listener);    //这个接口是对外暴露的,用于增加类似于监听器作用的订阅对象。
    
    /**
     * 当记录修改事件发生时,通知所有监听器
     * @param changeType 事件类型
     * @param object 被改变的对象
     */
    void notifyListener(String changeType, Object object, Class name); //这个是向内提供的,开始我还很奇怪,为什么会让系统自己调用自己提供的dubbo服务,而不是将接口写在core中,不对外暴露,后来我发现在接口的实现过程中,addListener的listeners是公用的,为了onChange时容易获得listeners,所以将逻辑写在dubbo接口中,保证listeners的全局作用
    
    /**
     * 返回回调服务目前的状态,以判定其工作是否正常
     * @return 0:表明回调服务工作正常,其他:表明回调服务无法正常工作
     */
    int isActive();
}

dubbo接口的实现

package com.enjoyor.soa.traffic.server.ubms.service.dubbo.impl.callback;

import java.util.ArrayList;
import java.util.List;

import com.enjoyor.soa.traffic.api.ubms.service.CallbackListener;
import com.enjoyor.soa.traffic.api.ubms.service.CallbackService;

public class CallbackServiceImpl implements CallbackService {

    private final List<CallbackListener> listeners = new ArrayList<CallbackListener>();

    @Override
    public void addListener(CallbackListener listener) {
        // TODO Auto-generated method stub
        listeners.add(listener);
    }

    @Override
    public void notifyListener(String changeType, Object object, Class name) {
        // TODO Auto-generated method stub

        for (CallbackListener listener : listeners) {
            try {
                listener.update(changeType, object, name);//对外回调的接口
            } catch (Throwable t) {
                if (listeners.indexOf(listener) >= 0) {
                    listeners.remove(listener);
                }
            }
        }
    }

    @Override
    public int isActive() {
        return 0;
    }
}

对外回调的接口:

import com.alibaba.dubbo.config.annotation.Service;

/**
 * 提供内容变化监听功能的接口
 * @author yuankun
 * @version V1.0
 */
@Service(protocol = { "dubbo" })
public interface CallbackListener {
    
    /**
     * 得到监听器通知后的响应方法
     * @param changeType 事件类型
     * @param object 被修改的对象
     */
    void update(String changeType, Object object, Class name);
}

 

服务端通知过程,更新时通知:

public ResultPojo addDeptInfo(String token, DeptInfoDto deptInfoDto) {
        try {
            if(checkToken(token))
            {
                List<DeptInfoPojo> list = this.deptInfoService.getDeptInfo(deptInfoDto.getDeptId(), null, null, null, null);
                if(list.size()>0){
                    return ResultHelper.getResult(EnumAppCode.PARAM_NAME_EXISTS);
                }
                DeptInfoPojo deptInfoPojo = this.dtoToPojo(deptInfoDto);
                int result = this.deptInfoService.addDeptInfo(getUserNameByToken(token), deptInfoPojo);
                this.notify(result, "addDeptInfo", deptInfoDto,DeptInfoDto.class);//!!!
                return ResultHelper.getResult(result);
            }
            else 
            {
                return ResultHelper.getResult(EnumAppCode.TOKEN_INVALID);
            }
        } catch (Exception ex) {
            return ResultHelper.getResult(ex);
        }
    }
/**
     * 回调Dubbo服务
     * @param result
     * @param type
     * @param obj
     */
    private CallbackService getCallbackService() 
    {
        CallbackService service = (CallbackService) SpringContextUtil.getBean("callbackService", CallbackService.class);
        //
        return service;
    }
    
    public void notify(int result, String type, Object obj, Class name)
    {
        if (result > 0) {
            if(null != this.getCallbackService())
            {
                this.getCallbackService().notifyListener(type, obj, name);
            }
        }
    }

 

 

 

客户端 登陆(uums)的代码:

dubbo接口的调用,增加相应的监听:

import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.enjoyor.soa.traffic.api.ubms.dto.DeptInfoDto;
import com.enjoyor.soa.traffic.api.ubms.dto.PersonInfoDto;
import com.enjoyor.soa.traffic.api.ubms.service.CallbackService;
import com.enjoyor.soa.traffic.server.uums.service.dubbo.invoke.DubboContext;
import com.enjoyor.soa.traffic.server.uums.service.dubbo.invoke.DubboDeptInfoServiceInvoke;
import com.enjoyor.soa.traffic.server.uums.service.dubbo.invoke.DubboPerserInfoServiceInvoke;
import com.enjoyor.soa.traffic.server.uums.service.dubbo.invoke.DubboUbmsCallbackListener;

public class DubboUbmsCallbackThread implements Runnable {
    
    
    public BlockingQueue<Map<String, Object>> queueReceive = new LinkedBlockingQueue<Map<String,Object>>();
    
    
//    public DubboUbmsCallbackThread(BlockingQueue<Map<String, Object>> queueReceive){
//        this.queueReceive=queueReceive;
//    }

    
    @SuppressWarnings("rawtypes")
    @Override
    public void run() {
        try {
            
            DubboUbmsCallbackListener dubboUbmsCallbackListener=new DubboUbmsCallbackListener(queueReceive);
            CallbackService callbackService=(CallbackService)DubboContext.getInstance().getContext().getBean("ubmsCallbackService");
            callbackService.addListener(dubboUbmsCallbackListener);
            
            
            while (true) {
                Map<String, Object> map=queueReceive.poll();
                if (map!=null) {
                    String operationType=map.get("operationType").toString();
                    Object object=map.get("value");
                    Class valueClass=(Class)map.get("class");

                    if (valueClass==DeptInfoDto.class) {
                        DubboDeptInfoServiceInvoke.getInstance().updateDeptInfoDtos(operationType, (DeptInfoDto)object);
                    }else if (valueClass==PersonInfoDto.class) {
                        DubboPerserInfoServiceInvoke.getInstance().updatePersonInfoDtos(operationType,(PersonInfoDto) object);
                    }
//                    switch (valueClass.getName()) {
//                    case deptInfoDtoClassName:
//                        DubboDeptInfoServiceInvoke.getInstance().updateDeptInfoDtos(operationType, (DeptInfoDto)map.get("value"));
//                        break;
//                    case "PersonInfoDto":
//                    DubboPerserInfoServiceInvoke.getInstance().updatePersonInfoDtos(operationType,(PersonInfoDto) object);
//                    default:
//                        break;
//                    }
                }else {
                    Thread.sleep(100);
                }
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

回调接口的实现:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.enjoyor.soa.traffic.api.ubms.service.CallbackListener;

public class DubboUbmsCallbackListener implements CallbackListener {
    
    public BlockingQueue<Map<String, Object>> queueReceive = new LinkedBlockingQueue<Map<String,Object>>();
    
    public DubboUbmsCallbackListener(BlockingQueue<Map<String, Object>> queueReceive){
        this.queueReceive=queueReceive;
    }

    @Override
    public void update(String changeType, Object object, Class name) {
    
        try {
            Map<String, Object> map=new HashMap<String, Object>();
            
            map.put("operationType", changeType);
//            map.put("classType", value);
            map.put("value", object);
            map.put("class", name);
            this.queueReceive.put(map);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

}

 

 

Ajax的callBack作用类似,在调用了后台程序以后,继续执行的操作。比如callBack:"callBackName"   callBackName就相当于服务端的接口,可以客户端自己实现,不然就和success function一样了。没有实践过,根本不能说懂,还有jsonp里面的callback~

 

function rt(callback) {
if (typeof callback == "function") {
callback();
}
}

function callback(){
alert(2);
}

 <html>

  
<head>
  
<title>回调函数(callback)</title>
<script language="javascript" type="text/javascript">
function a(callback)
{   
    alert("我是parent函数a!");
    alert("调用回调函数");
    callback();
}
function b(){
alert("我是回调函数b");
  
}
function c(){
alert("我是回调函数c");
  
}
  
function test()
{
    a(b);
   a(c);
}
  
</script>
</head>
  
<body>
<h1>学习js回调函数</h1>
<button onClick=test()>click me</button>
<p>应该能看到调用了两个回调函数</p>
</body>
  
</html>
懂了,就是把函数当作参数传进去了,callback的具体叫什么没关系,如果不用call()。