以5s超时为例。超时的接口数据,就不要了,默认为空
1. Feign超时
feign:
client:
config:
default: #default默认为所有feign的超时配置如下,可以改为具体的feign服务名
connectTimeout: 1000 #单位毫秒
readTimeout: 1000 #单位毫秒
2. restTemplate超时(全局)
重写以下内容
@Configuration
public class HttpConfig {
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(10000);
httpRequestFactory.setConnectTimeout(10000);
httpRequestFactory.setReadTimeout(5000);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor());
return restTemplate;
}
}
3. restTemplate超时(指定接口,用注解实现切面拦截)
note: 当全局和指定接口的restTemplate都有时,有以下几种情况(全局超时时间:T1,指定接口超时时间:T2) 1)T1 ≥ T2:接口到达T2就会抛出 2)T1 < T2:接口到达T1就会抛出
1.定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TargetHttpTimeout {
int timeout() default -1;
}
2.切面拦截
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import static org.springframework.http.HttpStatus.OK;
@Slf4j
@Aspect
@Component
public class TargetHttpTimeoutAspect {
@Around("@annotation(TargetHttpTimeout)")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
TargetHttpTimeout targetHttpTimeout = methodSignature.getMethod().getAnnotation(TargetHttpTimeout.class);
final Object[] result = {null};
class CallableThread implements Callable<String> {
@Override
public String call() {
try {
long start = System.currentTimeMillis();
result[0] = joinPoint.proceed();
long end = System.currentTimeMillis();
log.info("[TargetHttpTimeout joinPoint.proceed]耗时:{}", end - start);
} catch (Throwable e) {
log.info("[TargetHttpTimeout joinPoint.proceed]异常:", e);
}
return OK.name();
}
}
Callable<String> callableThread = new CallableThread();
FutureTask<String> task = new FutureTask<>(callableThread);
new Thread(task).start();
try {
task.get(targetHttpTimeout.readTimeout(), TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.info("[TargetHttpTimeout joinPoint.proceed]超时:", e);
}
return result[0];
}
}
3.注解使用 java实现 @TargetHttpTimeout(timeout = 200) //通过修改此处timeout时间来实现接口获取数据超时问题
@TargetHttpTimeout(timeout = 200)
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(value = 500))
@Override
public ResponseEntity<String> getData(List<Long> projectIdList) {
String projectIds= StringUtil.listToString(projectIdList, ",");
String url = valueConfig.getOpenapiData() + "?projectIds={projectIds}";
Map<String, Object> params = new HashMap<>();
params.put("projectIds", projectIds);
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> httpEntity = new HttpEntity<>(null, headers);
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class, params);
return exchange;
}
|