理解spring源码中的回调

来源:互联网 发布:光大炒股软件下载 编辑:程序博客网 时间:2024/06/07 11:56
好久没更新博客了,每天忙着接收新知识,博客好久没更新了。今天从新更细起来。
最近看spring源码,发现里面很多回调函数,可小白的我不知道回调是什么,经过多方查询,现在终于明白了,再看hibernatetemplete,感觉明朗了许多。下面附上个人理解。
由于本人还在努力着想着大神迈进,所以对于目前菜鸟的我,水平有限,大神勿笑。
对于一件事情的认识,我喜欢和另一件事情对比加以理解。那么,什么是回调呢?首先看看:回调,同步和异步的区别
               例如:同步:Class A ------------------>class B   类A 中的一个方法,调用类B中的一个方法,而且必须等待类B中的方法返回结果后类A中的方法才能向下走,这便是同步,同步在我们的代码中用的最多,我们经常用到,但我们也许没有在意。
异步:一种类似消息或事件的机制。不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。
举个例子:用户需要把相片上传至某个服务器A上,然后服务器A把他们的照片取出并传送到另一台服务器B上进行审批,若没有通过则通知对方。其中用户上传和审批没有阻塞关系,但当审批不通过时,则需要调用A的方法通知对方。
           回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;


下边结合一个例子说明下:
<span style="background-color: rgb(153, 153, 153);"><span style="color:#ffffff;"></span></span>
//这是我们最传统的方式,加载驱动,建立连接,设置参数,执行查询,重复性操作太多,那么,我们能不能简化?public void update(User user){String sql="update user set pwd = ? where name = ?";Connection connection=ConnectionUtil.getConnection();try {PreparedStatement statement=connection.prepareStatement(sql);statement.setString(1, "小明");statement.setString(2, "123456");statement.executeQuery();} catch (SQLException e) {try {connection.rollback();} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();}finally{try {connection.commit();} catch (SQLException e) {e.printStackTrace();}ConnectionUtil.close(connection);}}

简化一下:
public final Object execute(String sql){Connection connection=ConnectionUtil.getConnection();try {PreparedStatement statement=connection.prepareStatement(sql);  Object result= doinstatement(statement);//由子类去实现  return result;} catch (SQLException e) {e.printStackTrace();}finally{ConnectionUtil.close(connection);}return null;}public abstract Object doinstatement(PreparedStatement statement)throws SQLException;}
子类代码:
public class JdbcTemeteInpl extends JdbcTemete {@Overridepublic Object doinstatement(PreparedStatement statement) throws SQLException {// statement.setString(1, "小明");statement.executeQuery();return null;}}
怎么调用呢?
JdbcTemete jdbcTemete=new JdbcTemeteInpl();jdbcTemete.execute("select * from user where name = ?");}
这样,我们把查询的方法抽取成了一个模板, 但是这还不简便,每次查询要继承一次模板,能不能再简便点呢?
我们把doinstatement()抽取到一个方法里面,变这样:
public abstract class JdbcCollBack {                         //我们把它叫做类B public abstract Object  doinstatement(PreparedStatement statement)throws SQLException;}
然后模板这样一个方法:
public Object doexecute(JdbcCollBack collBack) throws SQLException{  //这个是模板的方法,叫类A中的方法 在这个方法中需要调用B的方法Object result=collBack.doinstatement(getStatement());//但是在这里,需要传个参数,这个参数调用了类A中的方法return result;}
这样不好看,我们再封装,我们习惯用query
public Object query(JdbcCollBack collBack) throws SQLException{return doexecute(collBack);}
此时的查询,这样:

public Object get(String sql,final String name) throws SQLException{JDBCTemete.sql = sql;connection=ConnectionUtil.getConnection();     return query(new JdbcCollBack() {@Overridepublic Object doinstatement(PreparedStatement statement)throws SQLException {statement.setString(1, name);ResultSet resultSet=statement.executeQuery();while(resultSet.next()){String nameString=resultSet.getString("name");String passwString=resultSet.getString("pwd");User user=new User(nameString, passwString);return user;}return null;}});}
这样,我们就可以自己写find load update 等,只要return query(new JdbcCollBack());这是个匿名内部类回调
这怎么回事呢?
类A中的方法:doexecute(JdbcCollBack collBack) 需要类B,然后调用B 的方法---collBack.doinstatement(getStatement()),即A调B
类B 中的doinstatement(PreparedStatement statement)方法需要一个参数PreparedStatement ,这个参数由类A中的方法提供。B调用A
这样对PreparedStatement 的管理由交给了类A,这样就是回调。这是面向对象的回调,对于面向过程的回调,本人菜鸟一个不知道。

最后,我们来理解HibernateTemplate的原理:
HibernateTemplate:有一个很重要的方法:protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
下面看看怎么回事:
HibernateTemplate,我们用的较多的execute():
public Object execute(HibernateCallback action)        throws DataAccessException    {        return doExecute(action, false, false);//这里调用了<span style="font-family: Arial;">doExecute方法</span>    }
然后看看 doExecute方法源码:
这是个模板方法:
  protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
        throws DataAccessException
    {
        org.hibernate.Session session;
        boolean existingTransaction;
        FlushMode previousFlushMode;
        Assert.notNull(action, "Callback object must not be null");
        session = enforceNewSession ? SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession();
        existingTransaction = !enforceNewSession && (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory()));
        if(existingTransaction)
            logger.debug("Found thread-bound Session for HibernateTemplate");
        previousFlushMode = null;
        Object obj;
        try
        {
            previousFlushMode = applyFlushMode(session, existingTransaction);
            enableFilters(session);
//session代理
            org.hibernate.Session sessionToExpose = !enforceNativeSession && !isExposeNativeSession() ? createSessionProxy(session) : session;
          // 这里调用回调方法,回调方法由我们来实现
   Object result = action.doInHibernate(sessionToExpose);
            flushIfNecessary(session, existingTransaction);
            obj = result;
        }
        catch(HibernateException ex)
        {
            throw convertHibernateAccessException(ex);
        }
        catch(SQLException ex)
        {
            throw convertJdbcAccessException(ex);
        }
        catch(RuntimeException ex)
        {
            throw ex;
        }
        if(existingTransaction)
        {
            logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
            disableFilters(session);
            if(previousFlushMode != null)
                session.setFlushMode(previousFlushMode);
        } else
        if(isAlwaysUseNewSession())
            SessionFactoryUtils.closeSession(session);
        else
            SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
        return obj;
        Exception exception;
        exception;
        if(existingTransaction)
        {
            logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
            disableFilters(session);
            if(previousFlushMode != null)
                session.setFlushMode(previousFlushMode);
        } else
        if(isAlwaysUseNewSession())
            SessionFactoryUtils.closeSession(session);
        else
//关闭session 用hibernateTemelete不用关闭session
            SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
        throw exception;
    }


hibernate 中还有get load find 方法,他们是如何实现的呢?
以get为例:调用executeWithNativeSession()方法,
 public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)        throws DataAccessException    {        return executeWithNativeSession(new HibernateCallback() {            public Object doInHibernate(org.hibernate.Session session)                throws HibernateException            {                if(lockMode != null)                    return session.get(entityClass, id, lockMode);                else                    return session.get(entityClass, id);            }
然后看看这个方法:
结果还是调用doExecute()方法
public Object executeWithNativeSession(HibernateCallback action)    {        return doExecute(action, false, true);    }
可以看出,HibernateTemplate 中的核心方法是 doExecute 其他方法都调用这个方法,不过提供了不同的封装,而且session的管理由HibernateTemplate 来完成,对于session的开启,事物的提交,都有一个默认的设置。
由于我没有看清 executeWithNativeSession()让我纠结模板里面的get,find load 方法中的 doInHibernate(Session session)里面的session是谁传来的,现在终于清楚了。

好了到这里就结束了,每天进步一点点,总有一天你也能成为大神!水平有限,不喜勿碰!




















0 0
原创粉丝点击