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));
    }
}

RestTemplate

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)注解启动存储功能,并可以指定引用强度,

simple example

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

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

原创文章 131 获赞 175 访问量 32万+

猜你喜欢

转载自blog.csdn.net/lonelymanontheway/article/details/105344200