Spring大量使用模板模式封裝資源獲取、異常轉換、資源釋放等固定流程,業務邏輯通過回調接口注入。以JdbcTemplate查詢/更新為例,剖析execute模板方法與PreparedStatementCallback/StatementCallback回調接口的協作機制。
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// 簡單更新
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
// 參數化更新
jdbcTemplate.update("UPDATE user SET age = ? WHERE id = ?",
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1, 18);
ps.setString(2, "erica");
}
});
query(PreparedStatementCreator, PreparedStatementSetter, ResultSetExtractor)構建PreparedStatementCallback回調,內部:pss.setValues(ps)綁參→ps.executeQuery()→rse.extractData(rs)提取結果→finally關閉ResultSet。execute(PreparedStatementCreator, PreparedStatementCallback)模板方法:public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action) {
Connection con = DataSourceUtils.getConnection(getDataSource());
PreparedStatement ps = null;
try {
// 1. 獲取/轉換連接(NativeJdbcExtractor)
Connection conToUse = nativeJdbcExtractor != null ? nativeJdbcExtractor.getNativeConnection(con) : con;
// 2. 創建 PreparedStatement
ps = psc.createPreparedStatement(conToUse);
DataSourceUtils.applyTransactionTimeout(ps, getDataSource());
// 3. 回調執行業務邏輯
PreparedStatement psToUse = nativeJdbcExtractor != null ? nativeJdbcExtractor.getNativePreparedStatement(ps) : ps;
Object result = action.doInPreparedStatement(psToUse);
// 4. 警告檢查
throwExceptionOnWarningIfNotIgnoringWarnings(ps.getWarnings());
return result;
} catch (SQLException ex) {
// 5. 統一異常轉換
throw getExceptionTranslator().translate("executing PreparedStatementCallback [" + psc + "]", getSql(psc), ex);
} finally {
// 6. 資源清理(參數清理、關閉Statement、歸還連接)
if (psc instanceof ParameterDisposer) ((ParameterDisposer) psc).cleanupParameters();
JdbcUtils.closeStatement(ps);
DataSourceUtils.closeConnectionIfNecessary(con, getDataSource());
}
}
execute(String sql)構建StatementCallback(內部stmt.execute(sql)),調用execute(StatementCallback)模板方法:獲取連接→創建Statement→回調doInStatement→警告檢查→異常轉換→finally關閉Statement/歸還連接。流程與PreparedStatement版本高度一致,體現模板模式「固定骨架、可變回調」精髓。
doInPreparedStatement/doInStatement單一方法,易於測試與復用。