博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring中Template模式与callback的结合使用浅析
阅读量:5010 次
发布时间:2019-06-12

本文共 6740 字,大约阅读时间需要 22 分钟。

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 null     * @throws DataAccessException in case of SQL Maps errors     */    public 
T execute(SqlMapClientCallback
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 execute(SqlMapClientCallback
action) throws DataAccessException 该方法就是一个模板方法,方法的参数是一个回调对象。在模板方法中,将一些相同的处理过程模板化,比如获得数据库连接,处理事务,处理异常,关闭资源等等, 这些都是每一个sql执行时都要面临的相同的过程,所以我们将他们房子模板方法中。然后将不同的部分通过 callback 对象作为参数传入进去,这样将模板代码和非 模板代码进行了隔离。没有必要将模板代码每次都写一遍。

 

public Object queryForObject(final String statementName, final Object parameterObject)            throws DataAccessException {        return execute(new SqlMapClientCallback() {            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
() { 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
() { public Map doInSqlMapClient(SqlMapExecutor executor) throws SQLException { return executor.queryForMap(statementName, parameterObject, keyProperty); } }); }

 

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

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

public 
T execute(ConnectionCallback
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()); } }

 

转载于:https://www.cnblogs.com/digdeep/p/4515008.html

你可能感兴趣的文章
JVM垃圾回收机制
查看>>
结对编程2 微软学术搜索 第一部分——功能性bug
查看>>
vim 插件之vundle
查看>>
数据库多对多关联表(Python&MySQL)
查看>>
[实变函数]1.2 集合的运算
查看>>
第06天
查看>>
设计模式的征途—5.原型(Prototype)模式
查看>>
Fiddler中添加serverIP
查看>>
mysql的某个数据库拒绝访问的问题
查看>>
C# ~ 从 XML 到 Linq 到 Linq to XML
查看>>
常用汉字的五笔拆法
查看>>
1044: [HAOI2008]木棍分割 - BZOJ
查看>>
OSI与TCP/IP模型
查看>>
【IT笔试面试题整理】丑数
查看>>
敏捷开发一千零一问系列之六:业务人员怎样参与开发?
查看>>
双向链表
查看>>
RAL调用
查看>>
freemarker 设置文本内容超过一定长度 用省略号代替
查看>>
jQuery.reveal弹出层使用
查看>>
学习spring in action 第一天
查看>>