http接口超时方案
方案1:多个resttemplate,不同超时时间的使用不同的template,优点:简单,扩展起来复制粘贴,缺点:代码冗余,多个template占用内存不够优雅
方案2:单个resttemplate,调用过程中反射修改超时时间,优点:比较高端,缺点:可能有多线程问题,需要充分测试,反射影响一点点性能
方案3:使用OkHttpClient包装一层resttemplate,再使用OkHttpClient提供的拦截器,每次调用的时候拦截根据url修改超时时间,优点:优雅;使用RestTemplateInterceptor包装后,可以动态修改每个接口的超时时间。缺点:需要引用自己的resttemplate,autowire的地方需要修改。
dubbo接口超时方案
利用自带的dubbot的timeount属性设置超时时间:dubbo的超时时间可以设置在生产者和消费者,并且消费者可以覆盖生产者的配置,所以我们只需要关心消费者的配置
方法 > 接口 > 全局
同级别下消费 > 生产
不仅针对超时timeout属性,所有可配置属性都具备该优先级规则
有个小坑需要注意,在@Reference上设置的超时时间可能出现无效的情况,当存在多个@Reference配置时,程序启动的时候,会根据加载顺序进行加载并覆盖之前的配置,所以要想得到正确的配置,需要所有引用接口的地方的超时时间设置一样
http超时设置代码
1. 配置RestTemplate的bean
- import com.f4.ts.org.manager.constants.NumberConstant;
- import com.f4.ts.org.manager.interceptor.RestTemplateInterceptor;
- import okhttp3.ConnectionPool;
- import okhttp3.OkHttpClient;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
- import org.springframework.web.client.RestTemplate;
-
- import java.util.concurrent.TimeUnit;
-
- /**
- * restful风格模板配置
- *
- * @author tengqy
- * @create 2022-07-04 8:33
- * @date 2022/07/05
- */
- @Configuration
- public class RestTemplateConfig {
- /**
- * restful风格模板拦截器
- */
- @Autowired
- private RestTemplateInterceptor restTemplateInterceptor;
-
- /**
- * 企业restful风格模板
- *
- * @return {@link RestTemplate}
- */
- @Bean
- public RestTemplate enterpriseRestTemplate() {
- OkHttpClient.Builder builder = new OkHttpClient.Builder();
- builder.connectTimeout(NumberConstant.NUM_INT_1000, TimeUnit.MILLISECONDS).readTimeout(NumberConstant.NUM_INT_1000, TimeUnit.MILLISECONDS)
- .writeTimeout(NumberConstant.NUM_INT_1000, TimeUnit.MILLISECONDS)
- .connectionPool(new ConnectionPool(NumberConstant.NUM_INT_50,
- NumberConstant.NUM_INT_13, TimeUnit.MINUTES)).addInterceptor(restTemplateInterceptor);
- RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory(builder.build()));
- return restTemplate;
- }
- }
2. 配置拦截器
- import com.alibaba.fastjson.JSON;
- import com.f4.ts.org.manager.config.TimeOutConfig;
- import com.f4.ts.org.manager.constants.NumberConstant;
- import com.f4.ts.utils.StringUtils;
- import lombok.extern.slf4j.Slf4j;
- import okhttp3.Interceptor;
- import okhttp3.Request;
- import okhttp3.Response;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
-
- import javax.annotation.PostConstruct;
- import java.io.IOException;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.TimeUnit;
-
- /**
- * restful风格模板拦截器
- *
- * @author tengqy
- * @create 2022-07-04 8:35
- * @date 2022/07/05
- */
- @Component
- @Slf4j
- public class RestTemplateInterceptor implements Interceptor {
- /**
- * 时间配置
- */
- @Autowired
- private TimeOutConfig timeOutConfig;
-
-
- /**
- * 超时地图
- */
- private static Map
> timeoutMap = new ConcurrentHashMap<>(); -
- /**
- * 最后一次
- */
- private long lastTime;
-
-
- /**
- * 全部url
- */
- private static final String DEFAULT_URL = "*";
-
- /**
- * 初始化
- */
- @PostConstruct
- public void init() {
- lastTime = System.currentTimeMillis();
- String timeoutCof = timeOutConfig.getTimeoutCof();
- log.info("初始化http超时时间配置 {}", timeoutCof);
- if (StringUtils.isNotBlank(timeoutCof)) {
- String[] split = timeoutCof.split(";");
- for (String s : split) {
- String[] strings = s.split(",");
- String connectionTimeout = "2000";
- String readTimeout = "2000";
- String writeTimeout = "2000";
- if (strings.length == NumberConstant.NUM_INT_4) {
- connectionTimeout = strings[NumberConstant.NUM_INT_1];
- readTimeout = strings[NumberConstant.NUM_INT_2];
- writeTimeout = strings[NumberConstant.NUM_INT_3];
- }
- timeoutMap.put(strings[0], Arrays.asList(Integer.valueOf(connectionTimeout), Integer.valueOf(readTimeout),
- Integer.valueOf(writeTimeout)));
- }
- }
- timeoutMap.put(DEFAULT_URL, Arrays.asList(NumberConstant.NUM_INT_2000, NumberConstant.NUM_INT_2000, NumberConstant.NUM_INT_2000));
- log.info("初始化http超时时间配置结束 {}", JSON.toJSONString(timeoutMap));
- }
-
- /**
- * 拦截
- *
- * @param chain 链
- * @return {@link Response}
- * @throws IOException ioexception
- */
- @Override
- public Response intercept(Chain chain) throws IOException {
- if (System.currentTimeMillis() - lastTime > (long) NumberConstant.NUMBER_600000) {
- init();
- lastTime = System.currentTimeMillis();
- }
- Request request = chain.request();
- String requestUrl = request.url().toString();
- for (Map.Entry
> entry : timeoutMap.entrySet()) { - if (requestUrl.endsWith(entry.getKey())) {
- return chain.withConnectTimeout(entry.getValue().get(NumberConstant.NUM_INT_0), TimeUnit.MILLISECONDS)
- .withReadTimeout(entry.getValue().get(NumberConstant.NUM_INT_1), TimeUnit.MILLISECONDS)
- .withWriteTimeout(entry.getValue().get(NumberConstant.NUM_INT_2), TimeUnit.MILLISECONDS)
- .proceed(request);
- }
- }
- List
defaultTime = timeoutMap.get(DEFAULT_URL); - return chain.withConnectTimeout(defaultTime.get(NumberConstant.NUM_INT_0), TimeUnit.MILLISECONDS)
- .withReadTimeout(defaultTime.get(NumberConstant.NUM_INT_1), TimeUnit.MILLISECONDS)
- .withWriteTimeout(defaultTime.get(NumberConstant.NUM_INT_2), TimeUnit.MILLISECONDS)
- .proceed(request);
- }
- }
3. 动态配置接口的超时时间,可以配置到配置中心等地方
- import lombok.Data;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.stereotype.Component;
-
- /**
- * 时间配置
- *
- * @author tengqy
- * @create 2022-07-05 9:18
- * @date 2022/07/05
- */
- @Component
- @Data
- @ConfigurationProperties
- public class TimeOutConfig {
- /**
- * 超时
- */
- @Value("${http.timeout.conf:*,2000,2000,2000}")
- private String timeoutCof;
-
- /**
- * 得到超时
- *
- * @return {@link String}
- */
- public String getTimeoutCof() {
- return timeoutCof;
- }
-
- /**
- * 设置超时
- *
- * @param timeoutCof 超时咖啡
- */
- public void setTimeoutCof(String timeoutCof) {
- this.timeoutCof = timeoutCof;
- }
- }
超时时间配置如下
- http:
- timeout:
- conf: url1;url2,1000,2000,2000
其中,如果不配置超时时间,则默认超时时间都是2s/2s/2s,否则配置了超时时间则按照
接口,a,b,c; 配置,其中a、b、c分别为建立连接超时时间、读超时时间、写超时时间