理解spring源码中的回调

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

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

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

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

    <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是谁传来的,现在终于清楚了。

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


来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 理解spring源码中的回调

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏