zoukankan      html  css  js  c++  java
  • Spring中Template模式与callback的结合使用浅析

    Spring不论是与ibatis,还是与Hibernate的结合中,都使用到了Template模式与callback技术,来达到简化代码实现的目的。Template模式也即模板模式,用于对一些不太变化的流程进行模板化,与callback结合,可以将变化的部分出离出来,使用callback实现。然后根据不同的情况,向template注入不同的callback。那些模板代码就没有必要重复写了。我们看下spring和ibatis的结合中,Template和callback的使用:

    public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {
        // ... ...
        /**
         * Execute the given data access action on a SqlMapExecutor.
         * @param action callback object that specifies the data access action
         * @return a result object returned by the action, or <code>null</code>
         * @throws DataAccessException in case of SQL Maps errors
         */
        public <T> T execute(SqlMapClientCallback<T> action) throws DataAccessException {
            Assert.notNull(action, "Callback object must not be null");
            Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
    
            // We always need to use a SqlMapSession, as we need to pass a Spring-managed
            // Connection (potentially transactional) in. This shouldn't be necessary if
            // we run against a TransactionAwareDataSourceProxy underneath, but unfortunately
            // we still need it to make iBATIS batch execution work properly: If iBATIS
            // doesn't recognize an existing transaction, it automatically executes the
            // batch for every single statement...
    
            SqlMapSession session = this.sqlMapClient.openSession();
            if (logger.isDebugEnabled()) {
                logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
            }
            Connection ibatisCon = null;
    
            try {
                Connection springCon = null;
                DataSource dataSource = getDataSource();
                boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);
    
                // Obtain JDBC Connection to operate on...
                try {
                    ibatisCon = session.getCurrentConnection();
                    if (ibatisCon == null) {
                        springCon = (transactionAware ?
                                dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
                        session.setUserConnection(springCon);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
                        }
                    }
                    else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
                        }
                    }
                }
                catch (SQLException ex) {
                    throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
                }
    
                // Execute given callback...
                try {
                    return action.doInSqlMapClient(session);
                }
                catch (SQLException ex) {
                    throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
                }
                finally {
                    try {
                        if (springCon != null) {
                            if (transactionAware) {
                                springCon.close();
                            }
                            else {
                                DataSourceUtils.doReleaseConnection(springCon, dataSource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        logger.debug("Could not close JDBC Connection", ex);
                    }
                }
    
                // Processing finished - potentially session still to be closed.
            }
            finally {
                // Only close SqlMapSession if we know we've actually opened it
                // at the present level.
                if (ibatisCon == null) {
                    session.close();
                }
            }
        }
     
    public <T> T execute(SqlMapClientCallback<T> action) throws DataAccessException
    该方法就是一个模板方法,方法的参数是一个回调对象。在模板方法中,将一些相同的处理过程模板化,比如获得数据库连接,处理事务,处理异常,关闭资源等等,
    这些都是每一个sql执行时都要面临的相同的过程,所以我们将他们房子模板方法中。然后将不同的部分通过 callback 对象作为参数传入进去,这样将模板代码和非
    模板代码进行了隔离。没有必要将模板代码每次都写一遍。
        public Object queryForObject(final String statementName, final Object parameterObject)
                throws DataAccessException {
    
            return execute(new SqlMapClientCallback<Object>() {
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    return executor.queryForObject(statementName, parameterObject);
                }
            });
        }
    
        public List queryForList(final String statementName, final Object parameterObject)
                throws DataAccessException {
    
            return execute(new SqlMapClientCallback<List>() {
                public List doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    return executor.queryForList(statementName, parameterObject);
                }
            });
        }
    
        public Map queryForMap(
                final String statementName, final Object parameterObject, final String keyProperty)
                throws DataAccessException {
    
            return execute(new SqlMapClientCallback<Map>() {
                public Map doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    return executor.queryForMap(statementName, parameterObject, keyProperty);
                }
            });
        }

    我们看一下上面这些方法,都是借助模板方法来处理那些每次都相同的流程,然后传入一个自己实现的 callback 对象。模板会自动回调我们在 callback 对象中定义的方法。

    我们看下JdbcTemplate中的模板方法也是相似的:

        public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
            Assert.notNull(action, "Callback object must not be null");
    
            Connection con = DataSourceUtils.getConnection(getDataSource());
            try {
                Connection conToUse = con;
                if (this.nativeJdbcExtractor != null) {
                    // Extract native JDBC Connection, castable to OracleConnection or the like.
                    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
                }
                else {
                    // Create close-suppressing Connection proxy, also preparing returned Statements.
                    conToUse = createConnectionProxy(con);
                }
                return action.doInConnection(conToUse);
            }
            catch (SQLException ex) {
                // Release Connection early, to avoid potential connection pool deadlock
                // in the case when the exception translator hasn't been initialized yet.
                DataSourceUtils.releaseConnection(con, getDataSource());
                con = null;
                throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
            }
            finally {
                DataSourceUtils.releaseConnection(con, getDataSource());
            }
        }
  • 相关阅读:
    Android Activity中获取当前焦点的控件,自动化输入EditText
    Java Android 二进制文件读写
    Delphi 动态数组、静态数组、TBytes 的区别
    IIS日志分析工具-Log Parser
    信息安全等级保护三级系统基线要求判分标准之应用安全
    通过TCPView工具查看foxmail用exchange方式连接exchange时用什么端口
    Windows2008R2操作系统日志清理
    批量IP自动netcat脚本
    批量IP自动ping脚本
    批量移动AD用户到指定OU
  • 原文地址:https://www.cnblogs.com/digdeep/p/4515008.html
Copyright © 2011-2022 走看看