callback 回调

来源:互联网 发布:数据采集板卡 编辑:程序博客网 时间:2024/06/06 00:38

前段时间看Spring的源码,看到HibernateTemplate里的HibernateCallback(),实在有不明白,于是在网上找了些文章和代码,
自己也试着写了些代码,由于是半路出家,才疏学浅,太理论的东西说不上来,只有靠代码说明问题。如有不对的地方还请高手指教。

一、初步理解
先看看比较流行的老板、工人和工作汇报的例子
/**
*
*报告接口
*/
public interface Report{
    public String workReport();
}

/**
*
* 工作报告
*/
public class ReportImpl implements Report{
    /**
     * 返回要报告的工作信息
     *
     * @return 报告工作信息
     */
    public String workReport() {
        return "工作汇报 Report";
    }
}

/**
*
* 工人
*/
public class Worker{
    private String name;    //工人姓名
    private Boss boss;      //工人所属的老板

    public Worker(String name, Boss boss) {
        this.name = name;
        this.boss = boss;
    }
   
    public String getName() {
    return name;
    }

    /**
     * 开工
     * @param event  事件
     */
    public void doWork(Report report){
    System.out.println(name + ":开工大吉");
    for(int i=0; i<20000; i++){
    }
    System.out.println(name + ": 搞定~!");
    System.out.println(name + ": 向老板报告工作");
    boss.workerReport(this, report);
    }
}

/**
*
* 老板
*/
public class Boss {
    /**
     * 老板接收工人的工作汇报
     * @param worker 工人
     * @param report  报告
     */
    public void workerReport(Worker worker, Report report){
    System.out.println("老板收到工人 " + worker.getName() + " 的工作报告: " + report.workReport());
    }
}

/**
*
* 测试类
*/
public class Test {
    public static void main(String args[]){
        Boss boss = new Boss();

        Worker worker1 = new Worker("小盖",boss);
        Worker worker2 = new Worker("老巴",boss);

    Report reportA = new ReportImpl();
    Report reportB = new ReportImpl();

    worker1.doWork(reportA);
    worker2.doWork(reportB);
    }
}

输出结果
小盖:开工大吉
小盖: 搞定~!
小盖: 向老板报告工作
老板收到工人 小盖 的工作报告: 工作汇报 Report
老巴:开工大吉
老巴: 搞定~!
老巴: 向老板报告工作
老板收到工人 老巴 的工作报告: 工作汇报 Report


二、OK,让我们看看还有什么改进
看到上边的代码应该有点感觉了吧,但还是有可以改进的余地。
看看Boss类,Boss要见到Worker才知道workReport是谁的。
其实Boss不用知道有哪些Worker来他那里汇报过工作,只要看Report就可以了。

那我们修改一下Boss类和Worker类。

/**
*
* 老板
*/
public class Boss {
    /**
     * 老板接收工人的工作汇报
     * @param report  报告
     */
    public void workerReport(Report report){
    System.out.println("老板收到工人的工作报告: " + report.workReport());
    }
}

/**
*
* 工人
*/
public class Worker{
    private String name;    //工人姓名
    private Boss boss;      //工人所属的老板

    public Worker(String name, Boss boss) {
        this.name = name;
        this.boss = boss;
    }
   
    public String getName() {
    return name;
    }

    /**
     * 开工
     * @param event  事件
     */
    public void doWork(){
    System.out.println(name + ":开工大吉");
    for(int i=0; i<20000; i++){
    }
    System.out.println(name + ": 搞定~!");
    System.out.println(name + ": 向老板报告工作");
    //匿名内部类
    boss.workerReport(
        new Report(){
            public String workerReport(){
                return name + "的工作汇报 Report";
            }
        }

    );
    }
}

ReportImpl类!?这时可以不要了。

/**
*
* 测试类
*/
public class Test {
    public static void main(String args[]){
        Boss boss = new Boss();

        Worker worker1 = new Worker("小盖",boss);
        Worker worker2 = new Worker("老巴",boss);

    //这里不用再new Report了,这些让Worker自己去做

    worker1.doWork();
    worker2.doWork();
    }
}

输出结果和上边一样。我们可以看到匿名内部类的好处,是不用将Worker的实例传入到Report的实现类中。


三、看看Spring做了些什么
(Spring 2.5)
org.springframework.orm.hibernate3.HibernateTemplate
...
public Serializable save(final Object entity) throws DataAccessException {
        return (Serializable) executeWithNativeSession(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
                checkWriteOperationAllowed(session);
                return session.save(entity);
            }
        }
);
    }
...
public Object executeWithNativeSession(HibernateCallback action) {
        return doExecute(action, false, true);
    }
...
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
            throws DataAccessException {
        ...
    }
...

现在让我们模仿Spring写一个回调的练习代码

为了将注意力放到练习上,而不被Spring如何获得Session扰乱,所以写个MySession类,并且用String代替了传入的实例。

/**
 *
 *  练习类
 */
public class MySession {
    /**
         * @param obj
         */
    //用String代理了Object
    public String save(String obj){
        return "MySession.save " + obj;
    }

    /**
         * @param obj
         */   
    public String pudate(String obj){
        return "MySession.pudate " + obj;
    }
    ...
}

/**
 * Callback接口
 * 相当于HibernateCallback接口
 */
public interface HCallback {
    public String doInCallback(MySession session);
}

/**
 * HTemplate类
 * 相当于HibernateTemplate类
 */
public class HTemplate {
    /**
         * @param user
         */
    //用String代理了Object类
    public String save(final String object){
        System.out.println(object + ":我在 HTemplate的save 方法中");
        return executeWithNativeSession(
            new HCallback(){
                public String doInCallback(MySession session){
                    System.out.println(object + ":我在 HCallback的doInCallback 方法中");
                    return session.save(object);
                }
            }

        );
    }
   
    ...

    /**
         * @param hcallback 回调接口
         */
    public String executeWithNativeSession(HCallback hcallback){
        //由于不关心Spring中如何获得Session,所以练习代码中这里new了一个 MySession 实例
        MySession session = new MySession();

        return hcallback.doInCallback(session);
    }
}


/**
 * HDaoSupport
 * 相当于HibernateDaoSupport
 */
public class HDaoSupport {

    public HDaoSupport(){
    }

    public HTemplate getHTemplate() {
        return new HTemplate();
    }
}

/**
 * DaoImpl类
 *
 */
public class UserDaoImpl extends HiDaoSupport implements UserDao {

    /**
         * @param user
         */
    public String add(String user) {
        return this.getHTemplate().save(user);
    }
    ...
}

/**
*
* 测试类
*/
public class Test {
    public static void main(String args[]){
        UserDao userDao = new UserDaoImpl();
    String result = userDao.add("小贝");
    System.out.println(result);
    }
}

输出结果
小贝:我在 HTemplate的save 方法中
小贝:我在 HCallback的doInCallback 方法中
MySession.save 小贝


四、在Hibernate的项目中完成自己的回调
当项目中没有用到Spring时,那可以模仿写一个

/**
 * 回调接口
 *
 */
public interface HibernateCallback {

    public Object execute(Session session) throws HibernateException;
}

/**
 * 模板类
 *
 */
public class HibernateTemplate {

    public static Object run(HibernateCallback callback) throws HibernateException {
        Session session = null;
        Transaction tx = null;
        try{
            session = HibernateSessionFactory.getCurrentSession();
            tx = seesion.beginTransaction();
            //留意这里
            Object result = callback.execute(session);
            tx.commit();
            return result;
        } catch(HibernateException e){
            tx.rollback();
            return null;
        }
    }
}


/**
 *
 * HibernateSupport类
 */
public class HibernateSupport {

    public Object save(final Object object) throws HibernateException{
        //回调
        return HibernateTemplate.run(
            new HibernateCallback(){
                public Object execute(Session session) throws HibernateException{
                    return session.save(object);
                }
            }
        );
    }
    ...
    //其他方法
}


/**
 *
 * DaoSupport类
 */
public class DaoSupport {

    public DaoSupport(){
    }

    public HibernateSupport getHibernateSupport() throws HibernateException {
        return new HibernateSupport();
    }
}


/**
 *
 * Dao类
 */
public class UserDaoImpl extends DaoSupport implements UserDao{

    public void save(User user) throws HibernateException{
        this.getHibernateSupport().save(user);
    }
}

以上代码参考
http://lavasoft.blog.51cto.com/62575/90453
http://hi.baidu.com/johnsoncr/blog/item/2a782f4b592681f582025c13.html
感谢他们的分享

原创粉丝点击