前面已經說過命令模式,現在我們來看看spring框架中JdbcTemplate中使用的命令模式
首先先注入jdbctemplate 調用 queryForObject 方法
其實每個方法底層實現都一樣,就用這個舉例吧。點進去這個方法,一路跟進去,找到最深那個query方法
在中間一直都在構建查詢需要的參數,可以跳過,最深的query方法如下
@Override @Nullable 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 @Nullable public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; try { rs = stmt.executeQuery(sql); return rse.extractData(rs); } finally { JdbcUtils.closeResultSet(rs); } } @Override public String getSql() { return sql; } } return execute(new QueryStatementCallback()); }
這里面有個內部類 QueryStatementCallback 實現了 StatementCallback 接口
而這個接口只有一個方法
@Nullable T doInStatement(Statement stmt) throws SQLException, DataAccessException;
通過類圖可以看到這個接口還有好幾個具體實現類
上面說的QueryStatementCallback 只是其中一個,然后我們看看這個類具體實現方法 doInStatement
本質上就是調用這個方法的參數的 executeQuery 方法 執行sql。
最后就是創建了這個內部類的實例傳給 execute方法 ,點進去,
1 @Override 2 @Nullable 3 public <T> T execute(StatementCallback<T> action) throws DataAccessException { 4 Assert.notNull(action, "Callback object must not be null"); 5 6 Connection con = DataSourceUtils.getConnection(obtainDataSource()); 7 Statement stmt = null; 8 try { 9 stmt = con.createStatement(); 10 applyStatementSettings(stmt); 11 T result = action.doInStatement(stmt); 12 handleWarnings(stmt); 13 return result; 14 } 15 catch (SQLException ex) { 16 // Release Connection early, to avoid potential connection pool deadlock 17 // in the case when the exception translator hasn't been initialized yet. 18 String sql = getSql(action); 19 JdbcUtils.closeStatement(stmt); 20 stmt = null; 21 DataSourceUtils.releaseConnection(con, getDataSource()); 22 con = null; 23 throw translateException("StatementCallback", sql, ex); 24 } 25 finally { 26 JdbcUtils.closeStatement(stmt); 27 DataSourceUtils.releaseConnection(con, getDataSource()); 28 } 29 }
第11行,就是調用真正內部類的實現,在調用之前,需要構建方法所需參數stmt , 然后返回結果
那怎么和命令模式聯系起來呢?我們來和命令模式5種角色,對號入座:
Command 其實 就是 StatementCallback ,里面的doInStatement就是 命令方法。
CommandImpl 就是 QueryStatementCallback ,由命令的具體實現去調用真正的執行方法,真正的執行方法就是stmt的executeQuery()。
Receiver 呢?jdbctemplate 是沒有具體的,但是我們可以把 Statement 看做是這個receiver ,前面的命令模式說的是,命令的具體實現擁有接收者,並通過構造方法賦值,而template 它是把接收者當作參數傳遞,我覺得本質是一樣的
因為之前實例化命令的具體實現時,傳入接收者,當然先的構造一個接收者,而template 也是一樣,先構造statement 然后傳入。
Invoker 就相當於 public <T> T execute(StatementCallback<T> action) throws DataAccessException 這個方法。
Client 就相當於我們自己開發的應用程序。
可以看出這個invokrer 也是傳入不同的具體命令,執行不同的 命令,達到不一樣的結果。
參考了一些大佬的博客,結合自己的見解,如果有不對的地方,請指出哈。