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风格模板拦截器*/@Autowiredprivate RestTemplateInterceptor restTemplateInterceptor;/*** 企业restful风格模板** @return {@link RestTemplate}*/@Beanpublic 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 {/*** 时间配置*/@Autowiredprivate TimeOutConfig timeOutConfig;/*** 超时地图*/private static Map> timeoutMap = new ConcurrentHashMap<>();/*** 最后一次*/private long lastTime;/*** 全部url*/private static final String DEFAULT_URL = "*";/*** 初始化*/@PostConstructpublic 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*/@Overridepublic 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分别为建立连接超时时间、读超时时间、写超时时间
上一篇:C语言—指针进阶(详解篇)
下一篇:2022美亚个人赛复盘