RestTemplate 配置,拦截器配置的一些参数,和测试

博客围绕RestTemplate展开,提出参数配置、冷门用法及不启动项目测试等问题。解决效果包括可配置ClientHttpRequestFactory和拦截器,支持多次调用响应体流信息、记录请求日志等。还介绍了不启动项目直接测试RestTemplate的三种方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提出问题:怎样配置 RestTemplate的参数比较好呢?RestTemplate 有哪些冷门的用法与知识呢? 怎么不启动项目,直接在测试类中 测试 RestTemplate 呢?

解决效果:

0) 2个参数 ClientHttpRequestFactory 和 拦截器 可以配置

1) 支持多次调用  response body的流信息。( 默认 response 只能调用1次getBody() )

2) 记录请求日志,使用 拦截器 ClientHttpRequestInterceptor 

3) 更改 request 和response的 header 等信息,也可在拦截器内统一实现 

4) 支持异步操作(暂无)

5) 设置超时时间,否则可能会因为网络不稳定而失败而没有明显的通知信息。设置了超时后,会自动 抛出异常,并且被代码拦截后就可以很快知道了。

/**
 * @author storm
 * @date 2020-11-19  14:31
 */
@Slf4j
@Configuration
public class RestClientConfig {

    // 多个 拦截器,注册为Bean,方便后期 调用该方法 返回同一个单例Bean
    @Bean
    public List<ClientHttpRequestInterceptor> restInterceptor() {
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();

        // 作用:更改 request的 header 和uri 等信息,更改response的header等信息
        ClientHttpRequestInterceptor header = new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
                ClientHttpResponse response = execution.execute(request, body);
                response.getHeaders().add("Foo", "bar");
                return response;
            }
        };

        // log日志,记录请求时耗时和参数信息
        ClientHttpRequestInterceptor timer = new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
                StopWatch watch = new StopWatch();
                watch.start();

                ClientHttpResponse response = execution.execute(request, body);
                watch.stop();

                String time = String.valueOf(watch.getTime(TimeUnit.MILLISECONDS));
                response.getHeaders().add("cost-milliseconds", time);

                log.info("发送rest请求耗时 :{} ms,{} {} headers:{}", time, request.getMethod(), request.getURI(), request.getHeaders());
                return response;
            }
        };

        interceptors.add(timer);
        interceptors.add(header);

        return interceptors;
    }

    /**
     * 支持多次使用 response.getBody() 读取流, 参考 https://www.baeldung.com/spring-rest-template-interceptor
     */
    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory rqstFactory = new HttpComponentsClientHttpRequestFactory();
        rqstFactory.setConnectionRequestTimeout(1*1000); // 从pool池中获取可用连接的时间,1 s
        rqstFactory.setConnectTimeout(10*1000); // 与远程服务器建立一个新连接所需要的时间, 10 s
        rqstFactory.setReadTimeout(30*1000); // 数据包开始传输之前的等待时间, 30 s

        RestTemplate template = new RestTemplate(
                // 多次使用 getBody() response body
                new BufferingClientHttpRequestFactory(rqstFactory));

        List<ClientHttpRequestInterceptor> interceptors = template.getInterceptors();
        if (CollectionUtils.isEmpty(template.getInterceptors())) {
            interceptors = restInterceptor();
        } else {
            interceptors.addAll(restInterceptor());  // 无论调用几次该方法,总是获取的是容器中的相同的一个 单例Bean。这也是为什么 restInterceptor() 必须使用 @Bean 注解 
        }

        template.setInterceptors(interceptors);
        return template;
    }

}

测试

不启动项目,直接测试 ,方式有3: 1) main 方法 内各种 new 对象之后 调用 ;2)  @RunWith  + @Autowired 注入Bean对象调用;3)  不使用 @RunWith  + @Autowired 也能调用

1) 掠过

2) @RunWith  + @Autowired 注入Bean对象调用 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.*;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringJUnit4ClassRunner.class)  // 在该类中运行测试,提供一些 spring 的某些特性支持
@ContextConfiguration(classes = RestClientConfig.class) // 利用SpringJUnit4ClassRunner 特性注入 Bean
public class RestTemplateConfigTest {
 
    @Autowired  //利用SpringJUnit4ClassRunner特性,直接使用 @Autowired 注入 
    RestTemplate restTemplate;
 
    @Test
    public void test01() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);  // 指定传输参数的格式为 json
        HttpEntity<Object> request = new HttpEntity<Object>(null, headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://httpbin.org/post", request, String.class);
        assertThat(responseEntity.getHeaders()
                .get("Foo")
                .get(0), is(equalTo("bar")));

        System.out.println("大多时候,成功的解决了提出问题的人,就以为万事大吉。典型的 国产思维。这可不好呀,都是自己人。");
    }
}
 

3) 不使用 @RunWith  + @Autowired

public class RestTemplateConfigTest {
 
    @Test
    public void test02() {
        ApplicationContext context = new AnnotationConfigApplicationContext(RestClientConfig.class);
        RestTemplate restTemplate = context.getBean(RestTemplate.class);
        String object = restTemplate.getForObject("https://不要解决提出问题的人.ok?param=yes", String.class);
    }
}

 

补充几句:

RestTemplate 更多案例 

@Runwith 的 作用 如下所示,更多 使用例子参考 

<think>好的,我需要回答用户关于如何正确实例化SpringRestTemplate类的最佳实践。首先,我得回忆一下RestTemplate的基本用法相关配置。根据用户提供的引用内容,特别是引用[1]提到了通过配置类进行详细设置,比如超时时间,引用[3]提到日志增强器,引用[4]涉及微服务中的使用。 首先,直接实例化RestTemplate最简单,但可能在生产环境中不够灵活,比如无法统一配置超时或拦截器。然后,使用配置类(如RestTemplateConfig)通过@Bean方法创建实例,这样可以集中管理配置,比如设置连接池、超时时间、消息转换器等。需要确保在配置类上添加@Configuration注解,并通过@Bean返回RestTemplate实例。 接下来,用户可能需要在微服务环境中使用,比如结合服务发现,这时候可能需要使用@LoadBalanced注解,让RestTemplate能够解析服务名。引用[2]中的例子提到了服务调用时的URL格式,如http://USER-SERVICE/users/,这需要负载均衡的支持。 另外,关于日志记录,引用[3]提到了使用spring-rest-template-logger库来增强日志,方便监控HTTP流量。这可以通过添加ClientHttpRequestInterceptor来实现,或者在配置类中引入相关依赖配置。 还需要考虑连接池的问题,默认的RestTemplate使用的是简单的HttpURLConnection,可能不够高效,使用Apache HttpClient或OkHttp3会更适合高并发场景。需要添加相应的依赖,并在配置时指定HttpClient。 异常处理也是关键,RestTemplate默认在4xx或5xx状态码时抛出异常,需要配置ErrorHandler来覆盖默认行为,或者在使用时捕获异常,如引用[2]中的try-catch块。 最后,在Spring Boot中自动注入RestTemplate实例时,确保配置类被组件扫描到,并且通过@Autowired注入。同时,如果有多个RestTemplate实例,需要使用@Qualifier来区分。 总结步骤应该是:1. 使用配置类创建Bean;2. 配置连接参数拦截器;3. 集成负载均衡;4. 添加日志监控;5. 使用连接池优化性能;6. 异常处理配置。同时,结合用户提供的引用内容,适当加入引用标记,比如配置超时引用[1],日志增强引用[3]等。</think>### 如何正确实例化 Spring RestTemplate 类的最佳实践 #### 1. **直接实例化(简单场景)** 对于简单需求,可以直接通过构造函数创建实例: ```java RestTemplate restTemplate = new RestTemplate(); ``` 但这种方式缺乏统一配置管理,适用于测试或简单场景。 #### 2. **通过配置类集中管理(推荐)** 通过 `@Configuration` 类定义 Bean,实现全局配置(如超时、拦截器)[^1]: ```java @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); // 设置连接超时读取超时(需配置具体HttpClient实现) restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); return restTemplate; } } ``` 在服务中通过 `@Autowired` 注入: ```java @Autowired private RestTemplate restTemplate; ``` #### 3. **配置连接参数优化性能** 使用连接池(如 Apache HttpClient)提升性能: ```java @Bean public RestTemplate restTemplate() { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(100); // 最大连接数 connectionManager.setDefaultMaxPerRoute(20); // 单路由最大连接数 CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .build(); return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient)); } ``` 需添加依赖: ```xml <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> ``` #### 4. **集成负载均衡(微服务场景)** 在 Spring Cloud 中,通过 `@LoadBalanced` 注解支持服务名解析[^4]: ```java @Bean @LoadBalanced public RestTemplate loadBalancedRestTemplate() { return new RestTemplate(); } ``` 调用时使用服务名代替具体 IP: ```java String response = restTemplate.getForObject("http://USER-SERVICE/users/{id}", String.class, userId); ``` #### 5. **添加日志拦截器** 通过自定义拦截器记录请求/响应详情[^3]: ```java @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add((request, body, execution) -> { System.out.println("Request: " + request.getURI()); return execution.execute(request, body); }); return restTemplate; } ``` 或引入 `spring-rest-template-logger` 库实现更完善的日志监控。 #### 6. **异常处理** 覆盖默认的 `DefaultResponseErrorHandler` 以避免 4xx/5xx 状态码抛出异常: ```java restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override public void handleError(ClientHttpResponse response) throws IOException { // 自定义异常处理逻辑 } }); ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值