Spring框架JdbcTemplate所用的命令模式之我見

概述

最近回顧了一下設計模式。想到Spring框架中,使用設計模式挺多的。于是搜索了一下Spring中有沒有使用命令模式?
參照:命令模式淺析,然后對Spring中的JdbcTemplate類進行了源碼閱讀,現(xiàn)在就命令模式,對JdbcTemplate中的部分代碼做一下解讀。

命令模式簡介

在軟件設計中,我們經(jīng)常需要向某些對象發(fā)送請求,但是并不知道請求的接收者是誰,也不知道被請求的操作是哪個,
我們只需在程序運行時指定具體的請求接收者即可,此時,可以使用命令模式來進行設計,
使得請求發(fā)送者與請求接收者消除彼此之間的耦合,讓對象之間的調用關系更加靈活。

舉個例子吧,將軍發(fā)布命令,士兵去執(zhí)行。其中有幾個角色:將軍(命令發(fā)布者)、士兵(命令的具體執(zhí)行者)、命令(連接將軍和士兵)。
Invoker是調用者(將軍),Receiver是被調用者(士兵),MyCommand是命令,實現(xiàn)了Command接口,持有接收對象

JdbcTemplate部分代碼解析

此類在工作中經(jīng)常被使用。其中的query方法,進行了大量的重載。
我們拿其中的一個重載方法來說:

    @Override
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return query(sql, new RowMapperResultSetExtractor<T>(rowMapper));
    }

這個方法調用了:

@Override
    public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
        Assert.notNull(sql, "SQL must not be null");
        Assert.notNull(rse, "ResultSetExtractor must not be null");
        if (logger.isDebugEnabled()) {
            logger.debug("Executing SQL query [" + sql + "]");
        }
        class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
            @Override
            public T doInStatement(Statement stmt) throws SQLException {
                ResultSet rs = null;
                try {
                    rs = stmt.executeQuery(sql);
                    ResultSet rsToUse = rs;
                    if (nativeJdbcExtractor != null) {
                        rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
                    }
                    return rse.extractData(rsToUse);
                }
                finally {
                    JdbcUtils.closeResultSet(rs);
                }
            }
            @Override
            public String getSql() {
                return sql;
            }
        }
        return execute(new QueryStatementCallback());
    }

其中,我們發(fā)現(xiàn)有一個匿名內部類:** QueryStatementCallback,它實現(xiàn)了 StatementCallback接口。
StatementCallback接口中有唯一的
doInStatement**方法:

T doInStatement(Statement stmt) throws SQLException, DataAccessException;

我們再接著往下看,

public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException

最后,調用了execute(new QueryStatementCallback())方法,并且把匿名內部類QueryStatementCallback的實例對象當做參數(shù)傳遞了過去。

@Override
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");

        Connection con = DataSourceUtils.getConnection(getDataSource());
        Statement stmt = null;
        try {
            Connection conToUse = con;
            if (this.nativeJdbcExtractor != null &&
                    this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
                conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
            }
            stmt = conToUse.createStatement();
            applyStatementSettings(stmt);
            Statement stmtToUse = stmt;
            if (this.nativeJdbcExtractor != null) {
                stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
            }
            T result = action.doInStatement(stmtToUse);
            handleWarnings(stmt);
            return result;
        }
        catch (SQLException ex) {
            // Release Connection early, to avoid potential connection pool deadlock
            // in the case when the exception translator hasn't been initialized yet.
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, getDataSource());
            con = null;
            throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
        }
        finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }

我們著重看一下這一行代碼:

T result = action.doInStatement(stmtToUse);

其中action參數(shù)是** StatementCallback**類型。

命令模式角色對應解析

在這個query查詢中,我們可以把 ** StatementCallback接口看做命令接口。
匿名內部類
QueryStatementCallback是該命令接口的一個具體實現(xiàn)命令。
QueryStatementCallback中,對 doInStatement接口進行了重寫,具體實現(xiàn)了命令的執(zhí)行。(相當于執(zhí)行命令的士兵,這里沒有用具體的類去單獨寫)
而命令調用者(將軍),是
T execute(StatementCallback<T> action)方法。根據(jù)傳遞的具體命令不同,最后action.doInStatement(stmtToUse)執(zhí)行的具體命令也就不同。
其中,
QueryStatementCallback的具體實現(xiàn)類還有以下幾個:

image.png

同時,我們可以看到命令調用者:
T execute(StatementCallback<T> action)**方法調用時,也對應傳遞了相應的具體命令。

image.png

備注

  • Spring版本:4.3
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容