理解spring源码中的回调

好久没更新博客了,每天忙着接收新知识,博客好久没更新了。今天从新更细起来。
最近看spring源码,发现里面很多回调函数,可小白的我不知道回调是什么,经过多方查询,现在终于明白了,再看hibernatetemplete,感觉明朗了许多。下面附上个人理解。
由于本人还在努力着想着大神迈进,所以对于目前菜鸟的我,水平有限,大神勿笑。
对于一件事情的认识,我喜欢和另一件事情对比加以理解。那么,什么是回调呢?首先看看:回调,同步和异步的区别
               例如:同步:Class A ——————>class B   类A 中的一个方法,调用类B中的一个方法,而且必须等待类B中的方法返回结果后类A中的方法才能向下走,这便是同步,同步在我们的代码中用的最多,我们经常用到,但我们也许没有在意。

异步:
一种类似消息或事件的机制。
不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。
举个例子:用户需要把相片上传至某个服务器A上,然后服务器A把他们的照片取出并传送到另一台服务器B上进行审批,若没有通过则通知对方。其中用户上传和审批没有阻塞关系,但当审批不通过时,则需要调用A的方法通知对方。
           回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
《理解spring源码中的回调》



下边结合一个例子说明下:

<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 {
	@Override
	public 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() {
		@Override
		public 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是谁传来的,现在终于清楚了。


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










    原文作者:Spring Cloud
    原文地址: https://blog.csdn.net/qq_29206465/article/details/50607017
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞