API 对接之模板方法
作者:Rubble
- 2022 年 4 月 19 日
本文字数:2499 字
阅读完需:约 8 分钟
定义
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
一个栗子
引用菜鸟教程的一个例子
父类定义一个步骤/模板,一般会有默认的步骤实现,只留一个抽象方法留到实现类中实现。
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
复制代码
子类进行具体的实现
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
复制代码
public static void main(String[] args) {
Game game = new Football();
game.play();
}
复制代码
spring 中的模板
spring 框架中也提供了一些模板如 JdbcTemplate、RestTemplate、RestTemplate。
JdbcTemplate 只需传入要执行的方法 ConnectionCallback,其他工作交给模板处理。
// 构造函数注入了DataSource
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
/**
* 模板步骤
* 1. 打开链接 Connection
* 2. 执行action (sql)
* 3. 释放链接 releaseConnection
**/
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
try {
// Create close-suppressing Connection proxy, also preparing returned Statements.
Connection conToUse = createConnectionProxy(con);
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
String sql = getSql(action);
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("ConnectionCallback", sql, ex);
}
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
复制代码
redisTemplate 也类似,处理的业务逻辑更多些
获取链接
执行 action
关闭资源、断开链接
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = getRequiredConnectionFactory();
RedisConnection conn = null;
try {
if (enableTransactionSupport) {
// only bind resources in case of potential transaction synchronization
conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
} else {
conn = RedisConnectionUtils.getConnection(factory);
}
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
RedisConnection connToUse = preProcessConnection(conn, existingConnection);
boolean pipelineStatus = connToUse.isPipelined();
if (pipeline && !pipelineStatus) {
connToUse.openPipeline();
}
RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
T result = action.doInRedis(connToExpose);
// close pipeline
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
// TODO: any other connection processing?
return postProcessResult(result, connToUse, existingConnection);
} finally {
RedisConnectionUtils.releaseConnection(conn, factory, enableTransactionSupport);
}
}
复制代码
redisTemplate.opsForValue().get(key) 也是调用了 template 的 execute 方法。
public V get(Object key) {
return execute(new ValueDeserializingRedisCallback(key) {
@Override
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
return connection.get(rawKey);
}
}, true);
}
复制代码
API 对接之模板方法
api 对接通常需要 加入时间戳,根据一定规则进行签名
XxxApiTemplate
public class XxxApiTemplate {
private String key;
private String secret;
@Autowired
private RestTemplate restTemplate;
private HttpClient httpClient;
public XxxApiTemplate () {
}
public XxxApiTemplate (String key, String secret) {
this.key = key;
this.secret = secret;
}
public String get(String url, Map<String,String> params){
// params 加入时间戳
// sign 根据key、secret进行签名(MD5/AES)
// 处理url拼接参数
// 其他工作 如日志等
// 进行请求 httpClient、restTemplate
return restTemplate.getForObject(url,String.class);
}
public String post(String url, Map<String,String> params){
// 与get方法类似,处理参数方式不同
Object request = null;
return restTemplate.postForObject(url,request,String.class);
}
public void execute(CallBackAction action){
}
}
复制代码
至此模板方法介绍到这。 若你有收获,便是我最大的快乐。
划线
评论
复制
发布于: 刚刚阅读数: 2
Rubble
关注
还未添加个人签名 2021.06.01 加入
还未添加个人简介
评论