前面已经说过命令模式,现在我们来看看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 也是传入不同的具体命令,执行不同的 命令,达到不一样的结果。
参考了一些大佬的博客,结合自己的见解,如果有不对的地方,请指出哈。