Spring系列之模版方法汇总
模版方法
模版方法是一种设计模式。
定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。
类型:行为类模式
结构
模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:
- 抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
- 模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
- 钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。
抽象类的任务是搭建逻辑的框架,抽象类的好坏直接决定了程序是否稳定性。
实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。
优点
- 容易扩展:一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。
- 便于维护:对于模版方法模式来说,正是由于主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。
- 比较灵活:因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
适用场景
在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
Spring框架里面有着大量模版方法模式的实现类,一般都以Template结尾。Spring模板方法模式是模板方法模式和回调模式的结合。
Jdbc
JdbcTemplate
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
NamedParameterJdbcTemplate
上面的依赖也会引入这个API。
RestTemplate
核心API:
HttpMessageConverter:对象转换器
ClientHttpRequestFactory:默认是JDK的HttpURLConnection
ResponseErrorHandler:异常处理
ClientHttpRequestInterceptor:请求拦截器
方法:
getForObject/getForEntity/postForObject/postForEntity
exchange(可用于GET和POST)
execute
ErrorHandler
自定义异常处理,继承DefaultResponseErrorHandler,实现handleError()方法
下载文件
// 小文件
RequestEntity requestEntity = RequestEntity.get(uri).build();
ResponseEntity<byte[]> responseEntity = restTemplate.exchange(requestEntity, byte[].class);
byte[] downloadContent = responseEntity.getBody();
// 大文件
ResponseExtractor<ResponseEntity<File>> responseExtractor = new ResponseExtractor<ResponseEntity<File>>() {
@Override
public ResponseEntity<File> extractData(ClientHttpResponse response) throws IOException {
File rcvFile = File.createTempFile("rcvFile", "zip");
FileCopyUtils.copy(response.getBody(), new FileOutputStream(rcvFile));
return ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()).body(rcvFile);
}
};
File getFile = this.restTemplate.execute(targetUri, HttpMethod.GET, null, responseExtractor);
RestTemplateBuilder
构造器模式。SB没有提供任何自动配置的 RestTemplate bean,可以通过自动配置的 RestTemplateBuilder 来自定义 RestTemplate 实例。
实现RestTemplateCustomizer,重写customize()方法,可以利用RestTemplateBuilder
// 使用自定义器(customizer)配置所有hosts使用代理,除了 192.168.0.5 :
static class ProxyCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
@Override
public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}
}).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
AsyncRestTemplate
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
值得注意的是,在版本(有待确定)后被标记为Deprecated。
异步调用
@RequestMapping("/async")
public String asyncReq(){
String url = "http://localhost:8080/jsonAsync";
ListenableFuture<ResponseEntity<JSONObject>> future = asyncRestTemplate.getForEntity(url, JSONObject.class);
future.addCallback(new SuccessCallback<ResponseEntity<JSONObject>>() {
public void onSuccess(ResponseEntity<JSONObject> result) {
System.out.println(result.getBody().toJSONString());
}
}, new FailureCallback() {
public void onFailure(Throwable ex) {
System.out.println("onFailure:"+ex);
}
});
return "a async sample";
}
KeyValueTemplate
引入依赖即可使用:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
键值对模版方法,spring-data项目下键值对存储系统如spring-data-redis便依赖这个GAV。
官方文档,支持SpEL表达式。
KeyValueTemplate实现KeyValueOperations接口,该接口定义一系列spring-data常用的方法,如findById,findAll,findInRange,insert,update,delete,count等。
默认使用ConcurrentHashMap作为k-v存储结构。
@Bean
public KeyValueOperations keyValueTemplate() {
return new KeyValueTemplate(keyValueAdapter());
}
@Bean
public KeyValueAdapter keyValueAdapter() {
return new MapKeyValueAdapter(ConcurrentHashMap.class);
}
通过@KeySpace注解定义一个实体类。@EnableMapRepositories(mapType = WeakHashMap.class)
注解启动存储功能,并可以指定引用强度,
Redis
操作redis的模版方法有很多,只需要引入依赖:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
便能使用下面5个模版方法;spring-data-redis依赖spring-data-keyvalue。
RedisTemplate
使用示例:
// 注入Redis的模板
@Autowired
private RedisTemplate<String, String> template;
// 把模板当作ListOperations接口类型注入,也可以当作Value、Set、Zset、HashOperations接口类型注入
@Resource(name="redisTemplate")
private ListOperations<String, String> listOps;
public void addLink(String userId, URL url) {
// 使用注入的接口类型
listOps.leftPush(userId, url.toExternalForm());
// 直接使用模板
redisTemplate.boundListOps(userId).leftPush(url.toExternalForm());
}
StringRedisTemplate
继承RedisTemplate
RedisKeyValueTemplate
继承KeyValueTemplate
ReactiveRedisTemplate
ReactiveStringRedisTemplate
继承ReactiveRedisTemplate
JmsTemplate
JpaTemplate
MongoTemplate
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
HibernateTemplate
RetryTemplate
引入依赖:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
RetryTemplate实现接口RetryOperations
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2022-03-11 Impala SQL常见报错问题排查与解决记录
2019-03-11 Java 开发IDEA常用插件推荐