命令模式-Spring框架JdbcTemplate

14 篇文章 0 订阅
9 篇文章 0 订阅

概述
最近回顾了一下设计模式。想到Spring框架中,使用设计模式挺多的。于是搜索了一下Spring中有没有使用命令模式?
参照:命令模式浅析,然后对Spring中的JdbcTemplate类进行了源码阅读,现在就命令模式,对JdbcTemplate中的部分代码做一下解读。

命令模式简介
在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,
我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,
使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

举个例子吧,将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
Invoker是调用者(将军),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象

JdbcTemplate部分代码解析
此类在工作中经常被使用。其中的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());
    }

其中,我们发现有一个匿名内部类:** QueryStatementCallback,它实现了 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的实例对象当做参数传递了过去。

@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参数是** StatementCallback**类型。

命令模式角色对应解析
在这个query查询中,我们可以把 ** StatementCallback接口看做命令接口。
匿名内部类 QueryStatementCallback是该命令接口的一个具体实现命令。
在 QueryStatementCallback中,对 doInStatement接口进行了重写,具体实现了命令的执行。(相当于执行命令的士兵,这里没有用具体的类去单独写)
而命令调用者(将军),是 T execute(StatementCallback action)方法。根据传递的具体命令不同,最后action.doInStatement(stmtToUse)执行的具体命令也就不同。
其中, QueryStatementCallback的具体实现类还有以下几个:
image.png

同时,我们可以看到命令调用者: T execute(StatementCallback action)**方法调用时,也对应传递了相应的具体命令。
image.png
备注
Spring版本:4.3

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值