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

概述

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

命令模式簡介

在軟件設(shè)計(jì)中,我們經(jīng)常需要向某些對(duì)象發(fā)送請(qǐng)求炼彪,但是并不知道請(qǐng)求的接收者是誰吐根,也不知道被請(qǐng)求的操作是哪個(gè),
我們只需在程序運(yùn)行時(shí)指定具體的請(qǐng)求接收者即可辐马,此時(shí)拷橘,可以使用命令模式來進(jìn)行設(shè)計(jì),
使得請(qǐng)求發(fā)送者與請(qǐng)求接收者消除彼此之間的耦合喜爷,讓對(duì)象之間的調(diào)用關(guān)系更加靈活冗疮。

舉個(gè)例子吧,將軍發(fā)布命令檩帐,士兵去執(zhí)行术幔。其中有幾個(gè)角色:將軍(命令發(fā)布者)、士兵(命令的具體執(zhí)行者)轿塔、命令(連接將軍和士兵)特愿。
Invoker是調(diào)用者(將軍),Receiver是被調(diào)用者(士兵)勾缭,MyCommand是命令揍障,實(shí)現(xiàn)了Command接口,持有接收對(duì)象

JdbcTemplate部分代碼解析

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

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

這個(gè)方法調(diào)用了:

@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)有一個(gè)匿名內(nèi)部類:** QueryStatementCallback兜畸,它實(shí)現(xiàn)了 StatementCallback接口努释。
StatementCallback接口中有唯一的
doInStatement**方法:

T doInStatement(Statement stmt) throws SQLException, DataAccessException;

我們?cè)俳又驴矗?/p>

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

最后,調(diào)用了execute(new QueryStatementCallback())方法咬摇,并且把匿名內(nèi)部類QueryStatementCallback的實(shí)例對(duì)象當(dāng)做參數(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**類型。

命令模式角色對(duì)應(yīng)解析

在這個(gè)query查詢中肛鹏,我們可以把 ** StatementCallback接口看做命令接口逸邦。
匿名內(nèi)部類
QueryStatementCallback是該命令接口的一個(gè)具體實(shí)現(xiàn)命令。
QueryStatementCallback中在扰,對(duì) doInStatement接口進(jìn)行了重寫缕减,具體實(shí)現(xiàn)了命令的執(zhí)行。(相當(dāng)于執(zhí)行命令的士兵芒珠,這里沒有用具體的類去單獨(dú)寫)
而命令調(diào)用者(將軍)桥狡,是
T execute(StatementCallback<T> action)方法。根據(jù)傳遞的具體命令不同皱卓,最后action.doInStatement(stmtToUse)執(zhí)行的具體命令也就不同裹芝。
其中,
QueryStatementCallback的具體實(shí)現(xiàn)類還有以下幾個(gè):

image.png

同時(shí)好爬,我們可以看到命令調(diào)用者:
T execute(StatementCallback<T> action)**方法調(diào)用時(shí)局雄,也對(duì)應(yīng)傳遞了相應(yīng)的具體命令。

image.png

備注

  • Spring版本:4.3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末存炮,一起剝皮案震驚了整個(gè)濱河市炬搭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌穆桂,老刑警劉巖宫盔,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異享完,居然都是意外死亡灼芭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門般又,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彼绷,“玉大人,你說我怎么就攤上這事茴迁〖拿酰” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵堕义,是天一觀的道長猜旬。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么洒擦? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任椿争,我火速辦了婚禮,結(jié)果婚禮上熟嫩,老公的妹妹穿的比我還像新娘秦踪。我一直安慰自己,他們只是感情好掸茅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布洋侨。 她就那樣靜靜地躺著,像睡著了一般倦蚪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上边苹,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天陵且,我揣著相機(jī)與錄音,去河邊找鬼个束。 笑死慕购,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茬底。 我是一名探鬼主播沪悲,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阱表!你這毒婦竟也來了殿如?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤最爬,失蹤者是張志新(化名)和其女友劉穎涉馁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爱致,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烤送,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糠悯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帮坚。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖互艾,靈堂內(nèi)的尸體忽然破棺而出试和,到底是詐尸還是另有隱情,我是刑警寧澤忘朝,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布灰署,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溉箕。R本人自食惡果不足惜晦墙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肴茄。 院中可真熱鬧晌畅,春花似錦、人聲如沸寡痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拦坠。三九已至连躏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贞滨,已是汗流浹背入热。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晓铆,地道東北人勺良。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像骄噪,于是被迫代替她去往敵國和親尚困。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容